PageRenderTime 56ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 1ms

/DICK.B1/IronPython.Modules/nt.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 1616 lines | 1237 code | 269 blank | 110 comment | 226 complexity | 05172044dcb891d55e37f4083fef332a MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.ComponentModel;
  19. using System.Diagnostics;
  20. using System.Globalization;
  21. using System.IO;
  22. using System.Runtime.InteropServices;
  23. using System.Security.Cryptography;
  24. using Microsoft.Scripting;
  25. using Microsoft.Scripting.Runtime;
  26. using Microsoft.Scripting.Utils;
  27. using IronPython.Runtime;
  28. using IronPython.Runtime.Exceptions;
  29. using IronPython.Runtime.Operations;
  30. using IronPython.Runtime.Types;
  31. #if CLR2
  32. using Microsoft.Scripting.Math;
  33. #else
  34. using System.Numerics;
  35. #endif
  36. [assembly: PythonModule("nt", typeof(IronPython.Modules.PythonNT))]
  37. namespace IronPython.Modules {
  38. public static class PythonNT {
  39. public const string __doc__ = "Provides low-level operationg system access for files, the environment, etc...";
  40. #if !SILVERLIGHT
  41. private static Dictionary<int, Process> _processToIdMapping = new Dictionary<int, Process>();
  42. private static List<int> _freeProcessIds = new List<int>();
  43. private static int _processCount;
  44. #endif
  45. #region Public API Surface
  46. #if !SILVERLIGHT // FailFast
  47. public static void abort() {
  48. System.Environment.FailFast("IronPython os.abort");
  49. }
  50. #endif
  51. /// <summary>
  52. /// Checks for the specific permissions, provided by the mode parameter, are available for the provided path. Permissions can be:
  53. ///
  54. /// F_OK: Check to see if the file exists
  55. /// R_OK | W_OK | X_OK: Check for the specific permissions. Only W_OK is respected.
  56. /// </summary>
  57. public static bool access(CodeContext/*!*/ context, string path, int mode) {
  58. if (path == null) throw PythonOps.TypeError("expected string, got None");
  59. if (mode == F_OK) {
  60. return context.LanguageContext.DomainManager.Platform.FileExists(path);
  61. }
  62. #if !SILVERLIGHT
  63. // match the behavior of the VC C Runtime
  64. FileAttributes fa = File.GetAttributes(path);
  65. if ((fa & FileAttributes.Directory) != 0) {
  66. // directories have read & write access
  67. return true;
  68. }
  69. if ((fa & FileAttributes.ReadOnly) != 0 && (mode & W_OK) != 0) {
  70. // want to write but file is read-only
  71. return false;
  72. }
  73. return true;
  74. #else
  75. return false;
  76. #endif
  77. }
  78. #if !SILVERLIGHT // SetCurrentDirectory, FileInfo
  79. public static void chdir([NotNull]string path) {
  80. if (String.IsNullOrEmpty(path)) {
  81. throw PythonExceptions.CreateThrowable(WindowsError, PythonExceptions._WindowsError.ERROR_INVALID_NAME, "Path cannot be an empty string");
  82. }
  83. try {
  84. Directory.SetCurrentDirectory(path);
  85. } catch (Exception e) {
  86. throw ToPythonException(e, path);
  87. }
  88. }
  89. public static void chmod(string path, int mode) {
  90. FileInfo fi = new FileInfo(path);
  91. if ((mode & S_IWRITE) != 0) {
  92. fi.Attributes &= ~(FileAttributes.ReadOnly);
  93. } else {
  94. fi.Attributes |= FileAttributes.ReadOnly;
  95. }
  96. }
  97. #endif
  98. public static void close(CodeContext/*!*/ context, int fd) {
  99. PythonContext pythonContext = PythonContext.GetContext(context);
  100. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  101. pf.close();
  102. }
  103. #if !SILVERLIGHT
  104. /// <summary>
  105. /// single instance of environment dictionary is shared between multiple runtimes because the environment
  106. /// is shared by multiple runtimes.
  107. /// </summary>
  108. public static readonly object environ = new PythonDictionary(new EnvironmentDictionaryStorage());
  109. #endif
  110. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  111. public static readonly PythonType error = Builtin.OSError;
  112. public static void _exit(CodeContext/*!*/ context, int code) {
  113. PythonContext.GetContext(context).DomainManager.Platform.TerminateScriptExecution(code);
  114. }
  115. public static object fdopen(CodeContext/*!*/ context, int fd) {
  116. return fdopen(context, fd, "r");
  117. }
  118. public static object fdopen(CodeContext/*!*/ context, int fd, string mode) {
  119. return fdopen(context, fd, mode, 0);
  120. }
  121. public static object fdopen(CodeContext/*!*/ context, int fd, string mode, int bufsize) {
  122. // check for a valid file mode...
  123. PythonFile.ValidateMode(mode);
  124. PythonContext pythonContext = PythonContext.GetContext(context);
  125. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  126. return pf;
  127. }
  128. public static object fstat(CodeContext/*!*/ context, int fd) {
  129. PythonContext pythonContext = PythonContext.GetContext(context);
  130. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  131. if (pf.IsConsole) {
  132. return new stat_result(8192);
  133. }
  134. return lstat(pf.name);
  135. }
  136. public static string getcwd(CodeContext/*!*/ context) {
  137. return context.LanguageContext.DomainManager.Platform.CurrentDirectory;
  138. }
  139. public static string getcwdu(CodeContext/*!*/ context) {
  140. return context.LanguageContext.DomainManager.Platform.CurrentDirectory;
  141. }
  142. public static string _getfullpathname(CodeContext/*!*/ context, [NotNull]string/*!*/ dir) {
  143. PlatformAdaptationLayer pal = context.LanguageContext.DomainManager.Platform;
  144. try {
  145. return context.LanguageContext.DomainManager.Platform.GetFullPath(dir);
  146. } catch (ArgumentException) {
  147. // .NET validates the path, CPython doesn't... so we replace invalid chars with
  148. // Char.Maxvalue, get the full path, and then replace the Char.Maxvalue's back w/
  149. // their original value.
  150. string newdir = dir;
  151. if (IsWindows()) {
  152. if (newdir.Length >= 2 && newdir[1] == ':' &&
  153. (newdir[0] < 'a' || newdir[0] > 'z') && (newdir[0] < 'A' || newdir[0] > 'Z')) {
  154. // invalid drive, .NET will reject this
  155. if (newdir.Length == 2) {
  156. return newdir + Path.DirectorySeparatorChar;
  157. } else if (newdir[2] == Path.DirectorySeparatorChar) {
  158. return newdir;
  159. } else {
  160. return newdir.Substring(0, 2) + Path.DirectorySeparatorChar + newdir.Substring(2);
  161. }
  162. }
  163. if (newdir.Length > 2 && newdir.IndexOf(':', 2) != -1) {
  164. // : is an invalid char if it's not in the 2nd position
  165. newdir = newdir.Substring(0, 2) + newdir.Substring(2).Replace(':', Char.MaxValue);
  166. }
  167. if (newdir.Length > 0 && newdir[0] == ':') {
  168. newdir = Char.MaxValue + newdir.Substring(1);
  169. }
  170. }
  171. foreach (char c in Path.GetInvalidPathChars()) {
  172. newdir = newdir.Replace(c, Char.MaxValue);
  173. }
  174. // walk backwards through the path replacing the same characters. We should have
  175. // only updated the directory leaving the filename which we're fixing.
  176. string res = context.LanguageContext.DomainManager.Platform.GetFullPath(newdir);
  177. int curDir = dir.Length;
  178. for (int curRes = res.Length - 1; curRes >= 0; curRes--) {
  179. if (res[curRes] == Char.MaxValue) {
  180. for (curDir--; curDir >= 0; curDir--) {
  181. if (newdir[curDir] == Char.MaxValue) {
  182. res = res.Substring(0, curRes) + dir[curDir] + res.Substring(curRes + 1);
  183. break;
  184. }
  185. }
  186. }
  187. }
  188. return res;
  189. }
  190. }
  191. private static bool IsWindows() {
  192. return Environment.OSVersion.Platform == PlatformID.Win32NT ||
  193. Environment.OSVersion.Platform == PlatformID.Win32S ||
  194. Environment.OSVersion.Platform == PlatformID.Win32Windows;
  195. }
  196. #if !SILVERLIGHT
  197. public static int getpid() {
  198. return System.Diagnostics.Process.GetCurrentProcess().Id;
  199. }
  200. #endif
  201. public static List listdir(CodeContext/*!*/ context, [NotNull]string path) {
  202. if (path == String.Empty) {
  203. path = ".";
  204. }
  205. List ret = PythonOps.MakeList();
  206. try {
  207. addBase(context.LanguageContext.DomainManager.Platform.GetFileSystemEntries(path, "*"), ret);
  208. return ret;
  209. } catch (Exception e) {
  210. throw ToPythonException(e, path);
  211. }
  212. }
  213. //
  214. // lstat(path) -> stat result
  215. // Like stat(path), but do not follow symbolic links.
  216. //
  217. public static object lstat(string path) {
  218. return stat(path);
  219. }
  220. #if !SILVERLIGHT
  221. public static void mkdir(string path) {
  222. if (Directory.Exists(path))
  223. throw DirectoryExists();
  224. try {
  225. Directory.CreateDirectory(path);
  226. } catch (Exception e) {
  227. throw ToPythonException(e, path);
  228. }
  229. }
  230. public static void mkdir(string path, int mode) {
  231. if (Directory.Exists(path)) throw DirectoryExists();
  232. // we ignore mode
  233. try {
  234. Directory.CreateDirectory(path);
  235. } catch (Exception e) {
  236. throw ToPythonException(e, path);
  237. }
  238. }
  239. public static object open(CodeContext/*!*/ context, string filename, int flag) {
  240. return open(context, filename, flag, 0777);
  241. }
  242. private const int DefaultBufferSize = 4096;
  243. public static object open(CodeContext/*!*/ context, string filename, int flag, int mode) {
  244. try {
  245. FileMode fileMode = FileModeFromFlags(flag);
  246. FileAccess access = FileAccessFromFlags(flag);
  247. FileOptions options = FileOptionsFromFlags(flag);
  248. FileStream fs;
  249. if (access == FileAccess.Read && (fileMode == FileMode.CreateNew || fileMode == FileMode.Create || fileMode == FileMode.Append)) {
  250. // .NET doesn't allow Create/CreateNew w/ access == Read, so create the file, then close it, then
  251. // open it again w/ just read access.
  252. fs = new FileStream(filename, fileMode, FileAccess.Write, FileShare.None);
  253. fs.Close();
  254. fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, DefaultBufferSize, options);
  255. } else if(access == FileAccess.ReadWrite && fileMode == FileMode.Append) {
  256. fs = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, DefaultBufferSize, options);
  257. } else {
  258. fs = new FileStream(filename, fileMode, access, FileShare.ReadWrite, DefaultBufferSize, options);
  259. }
  260. string mode2;
  261. if (fs.CanRead && fs.CanWrite) mode2 = "w+";
  262. else if (fs.CanWrite) mode2 = "w";
  263. else mode2 = "r";
  264. if ((flag & O_BINARY) != 0) {
  265. mode2 += "b";
  266. }
  267. return PythonContext.GetContext(context).FileManager.AddToStrongMapping(PythonFile.Create(context, fs, filename, mode2));
  268. } catch (Exception e) {
  269. throw ToPythonException(e, filename);
  270. }
  271. }
  272. private static FileOptions FileOptionsFromFlags(int flag) {
  273. FileOptions res = FileOptions.None;
  274. if ((flag & O_TEMPORARY) != 0) {
  275. res |= FileOptions.DeleteOnClose;
  276. }
  277. if ((flag & O_RANDOM) != 0) {
  278. res |= FileOptions.RandomAccess;
  279. }
  280. if ((flag & O_SEQUENTIAL) != 0) {
  281. res |= FileOptions.SequentialScan;
  282. }
  283. return res;
  284. }
  285. public static PythonFile popen(CodeContext/*!*/ context, string command) {
  286. return popen(context, command, "r");
  287. }
  288. public static PythonFile popen(CodeContext/*!*/ context, string command, string mode) {
  289. return popen(context, command, mode, 4096);
  290. }
  291. public static PythonFile popen(CodeContext/*!*/ context, string command, string mode, int bufsize) {
  292. if (String.IsNullOrEmpty(mode)) mode = "r";
  293. ProcessStartInfo psi = GetProcessInfo(command);
  294. psi.CreateNoWindow = true; // ipyw shouldn't create a new console window
  295. Process p;
  296. PythonFile res;
  297. try {
  298. switch (mode) {
  299. case "r":
  300. psi.RedirectStandardOutput = true;
  301. p = Process.Start(psi);
  302. res = new POpenFile(context, command, p, p.StandardOutput.BaseStream, "r");
  303. break;
  304. case "w":
  305. psi.RedirectStandardInput = true;
  306. p = Process.Start(psi);
  307. res = new POpenFile(context, command, p, p.StandardInput.BaseStream, "w");
  308. break;
  309. default:
  310. throw PythonOps.ValueError("expected 'r' or 'w' for mode, got {0}", mode);
  311. }
  312. } catch (Exception e) {
  313. throw ToPythonException(e);
  314. }
  315. return res;
  316. }
  317. public static PythonTuple popen2(CodeContext/*!*/ context, string command) {
  318. return popen2(context, command, "t");
  319. }
  320. public static PythonTuple popen2(CodeContext/*!*/ context, string command, string mode) {
  321. return popen2(context, command, "t", 4096);
  322. }
  323. public static PythonTuple popen2(CodeContext/*!*/ context, string command, string mode, int bufsize) {
  324. if (String.IsNullOrEmpty(mode)) mode = "t";
  325. if (mode != "t" && mode != "b") throw PythonOps.ValueError("mode must be 't' or 'b' (default is t)");
  326. if (mode == "t") mode = String.Empty;
  327. try {
  328. ProcessStartInfo psi = GetProcessInfo(command);
  329. psi.RedirectStandardInput = true;
  330. psi.RedirectStandardOutput = true;
  331. psi.CreateNoWindow = true; // ipyw shouldn't create a new console window
  332. Process p = Process.Start(psi);
  333. return PythonTuple.MakeTuple(new POpenFile(context, command, p, p.StandardInput.BaseStream, "w" + mode),
  334. new POpenFile(context, command, p, p.StandardOutput.BaseStream, "r" + mode));
  335. } catch (Exception e) {
  336. throw ToPythonException(e);
  337. }
  338. }
  339. public static PythonTuple popen3(CodeContext/*!*/ context, string command) {
  340. return popen3(context, command, "t");
  341. }
  342. public static PythonTuple popen3(CodeContext/*!*/ context, string command, string mode) {
  343. return popen3(context, command, "t", 4096);
  344. }
  345. public static PythonTuple popen3(CodeContext/*!*/ context, string command, string mode, int bufsize) {
  346. if (String.IsNullOrEmpty(mode)) mode = "t";
  347. if (mode != "t" && mode != "b") throw PythonOps.ValueError("mode must be 't' or 'b' (default is t)");
  348. if (mode == "t") mode = String.Empty;
  349. try {
  350. ProcessStartInfo psi = GetProcessInfo(command);
  351. psi.RedirectStandardInput = true;
  352. psi.RedirectStandardOutput = true;
  353. psi.RedirectStandardError = true;
  354. psi.CreateNoWindow = true; // ipyw shouldn't create a new console window
  355. Process p = Process.Start(psi);
  356. return PythonTuple.MakeTuple(new POpenFile(context, command, p, p.StandardInput.BaseStream, "w" + mode),
  357. new POpenFile(context, command, p, p.StandardOutput.BaseStream, "r" + mode),
  358. new POpenFile(context, command, p, p.StandardError.BaseStream, "r+" + mode));
  359. } catch (Exception e) {
  360. throw ToPythonException(e);
  361. }
  362. }
  363. public static void putenv(string varname, string value) {
  364. try {
  365. System.Environment.SetEnvironmentVariable(varname, value);
  366. } catch (Exception e) {
  367. throw ToPythonException(e);
  368. }
  369. }
  370. #endif
  371. public static string read(CodeContext/*!*/ context, int fd, int buffersize) {
  372. if (buffersize < 0) {
  373. throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, PythonErrorNumber.EINVAL, "Invalid argument");
  374. }
  375. try {
  376. PythonContext pythonContext = PythonContext.GetContext(context);
  377. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  378. return pf.read();
  379. } catch (Exception e) {
  380. throw ToPythonException(e);
  381. }
  382. }
  383. #if !SILVERLIGHT
  384. public static void remove(string path) {
  385. UnlinkWorker(path);
  386. }
  387. #endif
  388. public static void rename(string src, string dst) {
  389. try {
  390. Directory.Move(src, dst);
  391. } catch (Exception e) {
  392. throw ToPythonException(e);
  393. }
  394. }
  395. public static void rmdir(string path) {
  396. try {
  397. Directory.Delete(path);
  398. } catch (Exception e) {
  399. throw ToPythonException(e, path);
  400. }
  401. }
  402. #if !SILVERLIGHT
  403. /// <summary>
  404. /// spawns a new process.
  405. ///
  406. /// If mode is nt.P_WAIT then then the call blocks until the process exits and the return value
  407. /// is the exit code.
  408. ///
  409. /// Otherwise the call returns a handle to the process. The caller must then call nt.waitpid(pid, options)
  410. /// to free the handle and get the exit code of the process. Failure to call nt.waitpid will result
  411. /// in a handle leak.
  412. /// </summary>
  413. public static object spawnl(CodeContext/*!*/ context, int mode, string path, params object[] args) {
  414. return SpawnProcessImpl(context, MakeProcess(), mode, path, args);
  415. }
  416. /// <summary>
  417. /// spawns a new process.
  418. ///
  419. /// If mode is nt.P_WAIT then then the call blocks until the process exits and the return value
  420. /// is the exit code.
  421. ///
  422. /// Otherwise the call returns a handle to the process. The caller must then call nt.waitpid(pid, options)
  423. /// to free the handle and get the exit code of the process. Failure to call nt.waitpid will result
  424. /// in a handle leak.
  425. /// </summary>
  426. public static object spawnle(CodeContext/*!*/ context, int mode, string path, params object[] args) {
  427. if (args.Length < 1) {
  428. throw PythonOps.TypeError("spawnle() takes at least three arguments ({0} given)", 2 + args.Length);
  429. }
  430. object env = args[args.Length - 1];
  431. object[] slicedArgs = ArrayUtils.RemoveFirst(args);
  432. Process process = MakeProcess();
  433. SetEnvironment(process.StartInfo.EnvironmentVariables, env);
  434. return SpawnProcessImpl(context, process, mode, path, slicedArgs);
  435. }
  436. /// <summary>
  437. /// spawns a new process.
  438. ///
  439. /// If mode is nt.P_WAIT then then the call blocks until the process exits and the return value
  440. /// is the exit code.
  441. ///
  442. /// Otherwise the call returns a handle to the process. The caller must then call nt.waitpid(pid, options)
  443. /// to free the handle and get the exit code of the process. Failure to call nt.waitpid will result
  444. /// in a handle leak.
  445. /// </summary>
  446. public static object spawnv(CodeContext/*!*/ context, int mode, string path, object args) {
  447. return SpawnProcessImpl(context, MakeProcess(), mode, path, args);
  448. }
  449. /// <summary>
  450. /// spawns a new process.
  451. ///
  452. /// If mode is nt.P_WAIT then then the call blocks until the process exits and the return value
  453. /// is the exit code.
  454. ///
  455. /// Otherwise the call returns a handle to the process. The caller must then call nt.waitpid(pid, options)
  456. /// to free the handle and get the exit code of the process. Failure to call nt.waitpid will result
  457. /// in a handle leak.
  458. /// </summary>
  459. public static object spawnve(CodeContext/*!*/ context, int mode, string path, object args, object env) {
  460. Process process = MakeProcess();
  461. SetEnvironment(process.StartInfo.EnvironmentVariables, env);
  462. return SpawnProcessImpl(context, process, mode, path, args);
  463. }
  464. private static Process MakeProcess() {
  465. try {
  466. return new Process();
  467. } catch (Exception e) {
  468. throw ToPythonException(e);
  469. }
  470. }
  471. private static object SpawnProcessImpl(CodeContext/*!*/ context, Process process, int mode, string path, object args) {
  472. try {
  473. process.StartInfo.Arguments = ArgumentsToString(context, args);
  474. process.StartInfo.FileName = path;
  475. process.StartInfo.UseShellExecute = false;
  476. } catch (Exception e) {
  477. throw ToPythonException(e, path);
  478. }
  479. if (!process.Start()) {
  480. throw PythonOps.OSError("Cannot start process: {0}", path);
  481. }
  482. if (mode == P_WAIT) {
  483. process.WaitForExit();
  484. int exitCode = process.ExitCode;
  485. process.Close();
  486. return exitCode;
  487. }
  488. lock (_processToIdMapping) {
  489. int id;
  490. if (_freeProcessIds.Count > 0) {
  491. id = _freeProcessIds[_freeProcessIds.Count - 1];
  492. _freeProcessIds.RemoveAt(_freeProcessIds.Count - 1);
  493. } else {
  494. // process IDs are handles on CPython/Win32 so we match
  495. // that behavior and return something that is handle like. Handles
  496. // on NT are guaranteed to have the low 2 bits not set and users
  497. // could use these for their own purposes. We therefore match that
  498. // behavior here.
  499. _processCount += 4;
  500. id = _processCount;
  501. }
  502. _processToIdMapping[id] = process;
  503. return ScriptingRuntimeHelpers.Int32ToObject(id);
  504. }
  505. }
  506. /// <summary>
  507. /// Copy elements from a Python mapping of dict environment variables to a StringDictionary.
  508. /// </summary>
  509. private static void SetEnvironment(System.Collections.Specialized.StringDictionary currentEnvironment, object newEnvironment) {
  510. PythonDictionary env = newEnvironment as PythonDictionary;
  511. if (env == null) {
  512. throw PythonOps.TypeError("env argument must be a dict");
  513. }
  514. currentEnvironment.Clear();
  515. string strKey, strValue;
  516. foreach (object key in env.keys()) {
  517. if (!Converter.TryConvertToString(key, out strKey)) {
  518. throw PythonOps.TypeError("env dict contains a non-string key");
  519. }
  520. if (!Converter.TryConvertToString(env[key], out strValue)) {
  521. throw PythonOps.TypeError("env dict contains a non-string value");
  522. }
  523. currentEnvironment[strKey] = strValue;
  524. }
  525. }
  526. #endif
  527. /// <summary>
  528. /// Convert a sequence of args to a string suitable for using to spawn a process.
  529. /// </summary>
  530. private static string ArgumentsToString(CodeContext/*!*/ context, object args) {
  531. IEnumerator argsEnumerator;
  532. System.Text.StringBuilder sb = null;
  533. if (!PythonOps.TryGetEnumerator(context, args, out argsEnumerator)) {
  534. throw PythonOps.TypeError("args parameter must be sequence, not {0}", DynamicHelpers.GetPythonType(args));
  535. }
  536. bool space = false;
  537. try {
  538. // skip the first element, which is the name of the command being run
  539. argsEnumerator.MoveNext();
  540. while (argsEnumerator.MoveNext()) {
  541. if (sb == null) sb = new System.Text.StringBuilder(); // lazy creation
  542. string strarg = PythonOps.ToString(argsEnumerator.Current);
  543. if (space) {
  544. sb.Append(' ');
  545. }
  546. if (strarg.IndexOf(' ') != -1) {
  547. sb.Append('"');
  548. // double quote any existing quotes
  549. sb.Append(strarg.Replace("\"", "\"\""));
  550. sb.Append('"');
  551. } else {
  552. sb.Append(strarg);
  553. }
  554. space = true;
  555. }
  556. } finally {
  557. IDisposable disposable = argsEnumerator as IDisposable;
  558. if (disposable != null) disposable.Dispose();
  559. }
  560. if (sb == null) return "";
  561. return sb.ToString();
  562. }
  563. #if !SILVERLIGHT
  564. public static void startfile(string filename, [DefaultParameterValue("open")]string operation) {
  565. System.Diagnostics.Process process = new System.Diagnostics.Process();
  566. process.StartInfo.FileName = filename;
  567. process.StartInfo.UseShellExecute = true;
  568. process.StartInfo.Verb = operation;
  569. try {
  570. process.Start();
  571. } catch (Exception e) {
  572. throw ToPythonException(e, filename);
  573. }
  574. }
  575. #endif
  576. [PythonType, DontMapIEnumerableToIter]
  577. public class stat_result : IList, IList<object> {
  578. private readonly object _mode, _size, _atime, _mtime, _ctime, _st_atime, _st_mtime, _st_ctime, _ino, _dev, _nlink, _uid, _gid;
  579. public const int n_fields = 13;
  580. public const int n_sequence_fields = 10;
  581. public const int n_unnamed_fields = 3;
  582. internal stat_result(int mode) : this(mode, BigInteger.Zero, BigInteger.Zero, BigInteger.Zero, BigInteger.Zero) {
  583. _mode = mode;
  584. }
  585. internal stat_result(int mode, BigInteger size, BigInteger st_atime, BigInteger st_mtime, BigInteger st_ctime) {
  586. _mode = mode;
  587. _size = size;
  588. _st_atime = _atime = TryShrinkToInt(st_atime);
  589. _st_mtime = _mtime = TryShrinkToInt(st_mtime);
  590. _st_ctime = _ctime = TryShrinkToInt(st_ctime);
  591. _ino = _dev = _nlink = _uid = _gid = ScriptingRuntimeHelpers.Int32ToObject(0);
  592. }
  593. public stat_result(CodeContext/*!*/ context, IList statResult, [DefaultParameterValue(null)]PythonDictionary dict) {
  594. // dict is allowed by CPython's stat_result, but doesn't seem to do anything, so we ignore it here.
  595. if (statResult.Count < 10) {
  596. throw PythonOps.TypeError("stat_result() takes an at least 10-sequence ({0}-sequence given)", statResult.Count);
  597. }
  598. _mode = statResult[0];
  599. _ino = statResult[1];
  600. _dev = statResult[2];
  601. _nlink = statResult[3];
  602. _uid = statResult[4];
  603. _gid = statResult[5];
  604. _size = statResult[6];
  605. _atime = statResult[7];
  606. _mtime = statResult[8];
  607. _ctime = statResult[9];
  608. object dictTime;
  609. if (statResult.Count >= 11) {
  610. _st_atime = TryShrinkToInt(statResult[10]);
  611. } else if (TryGetDictValue(dict, "st_atime", out dictTime)) {
  612. _st_atime = dictTime;
  613. } else {
  614. _st_atime = TryShrinkToInt(_atime);
  615. }
  616. if (statResult.Count >= 12) {
  617. _st_mtime = TryShrinkToInt(statResult[11]);
  618. } else if (TryGetDictValue(dict, "st_mtime", out dictTime)) {
  619. _st_mtime = dictTime;
  620. } else {
  621. _st_mtime = TryShrinkToInt(_mtime);
  622. }
  623. if (statResult.Count >= 13) {
  624. _st_ctime = TryShrinkToInt(statResult[12]);
  625. } else if (TryGetDictValue(dict, "st_ctime", out dictTime)) {
  626. _st_ctime = dictTime;
  627. } else {
  628. _st_ctime = TryShrinkToInt(_ctime);
  629. }
  630. }
  631. private static bool TryGetDictValue(PythonDictionary dict, string name, out object dictTime) {
  632. if (dict != null && dict.TryGetValue(name, out dictTime)) {
  633. dictTime = TryShrinkToInt(dictTime);
  634. return true;
  635. }
  636. dictTime = null;
  637. return false;
  638. }
  639. private static object TryShrinkToInt(object value) {
  640. if (!(value is BigInteger)) {
  641. return value;
  642. }
  643. return BigIntegerOps.__int__((BigInteger)value);
  644. }
  645. public object st_atime {
  646. get {
  647. return _st_atime;
  648. }
  649. }
  650. public object st_ctime {
  651. get {
  652. return _st_ctime;
  653. }
  654. }
  655. public object st_mtime {
  656. get {
  657. return _st_mtime;
  658. }
  659. }
  660. public object st_dev {
  661. get {
  662. return TryShrinkToInt(_dev);
  663. }
  664. }
  665. public object st_gid {
  666. get {
  667. return _gid;
  668. }
  669. }
  670. public object st_ino {
  671. get {
  672. return _ino;
  673. }
  674. }
  675. public object st_mode {
  676. get {
  677. return TryShrinkToInt(_mode);
  678. }
  679. }
  680. public object st_nlink {
  681. get {
  682. return TryShrinkToInt(_nlink);
  683. }
  684. }
  685. public object st_size {
  686. get {
  687. return _size;
  688. }
  689. }
  690. public object st_uid {
  691. get {
  692. return _uid;
  693. }
  694. }
  695. public static PythonTuple operator +(stat_result stat, object tuple) {
  696. PythonTuple tupleObj = tuple as PythonTuple;
  697. if (tupleObj == null) {
  698. throw PythonOps.TypeError("can only concatenate tuple (not \"{0}\") to tuple", PythonTypeOps.GetName(tuple));
  699. }
  700. return stat.MakeTuple() + tupleObj;
  701. }
  702. public static bool operator >(stat_result stat, [NotNull]stat_result o) {
  703. return stat.MakeTuple() > PythonTuple.Make(o);
  704. }
  705. public static bool operator <(stat_result stat, [NotNull]stat_result o) {
  706. return stat.MakeTuple() < PythonTuple.Make(o);
  707. }
  708. public static bool operator >=(stat_result stat, [NotNull]stat_result o) {
  709. return stat.MakeTuple() >= PythonTuple.Make(o);
  710. }
  711. public static bool operator <=(stat_result stat, [NotNull]stat_result o) {
  712. return stat.MakeTuple() <= PythonTuple.Make(o);
  713. }
  714. public static bool operator >(stat_result stat, object o) {
  715. return true;
  716. }
  717. public static bool operator <(stat_result stat, object o) {
  718. return false;
  719. }
  720. public static bool operator >=(stat_result stat, object o) {
  721. return true;
  722. }
  723. public static bool operator <=(stat_result stat, object o) {
  724. return false;
  725. }
  726. public static PythonTuple operator *(stat_result stat, int size) {
  727. return stat.MakeTuple() * size;
  728. }
  729. public static PythonTuple operator *(int size, stat_result stat) {
  730. return stat.MakeTuple() * size;
  731. }
  732. public override string ToString() {
  733. return MakeTuple().ToString();
  734. }
  735. public string/*!*/ __repr__() {
  736. return ToString();
  737. }
  738. public PythonTuple __reduce__() {
  739. PythonDictionary timeDict = new PythonDictionary(3);
  740. timeDict["st_atime"] = st_atime;
  741. timeDict["st_ctime"] = st_ctime;
  742. timeDict["st_mtime"] = st_mtime;
  743. return PythonTuple.MakeTuple(
  744. DynamicHelpers.GetPythonTypeFromType(typeof(stat_result)),
  745. PythonTuple.MakeTuple(MakeTuple(), timeDict)
  746. );
  747. }
  748. #region ISequence Members
  749. //public object AddSequence(object other) {
  750. // return MakeTuple().AddSequence(other);
  751. //}
  752. //public object MultiplySequence(object count) {
  753. // return MakeTuple().MultiplySequence(count);
  754. //}
  755. public object this[int index] {
  756. get {
  757. return MakeTuple()[index];
  758. }
  759. }
  760. public object this[Slice slice] {
  761. get {
  762. return MakeTuple()[slice];
  763. }
  764. }
  765. public object __getslice__(int start, int stop) {
  766. return MakeTuple().__getslice__(start, stop);
  767. }
  768. public int __len__() {
  769. return MakeTuple().__len__();
  770. }
  771. public bool __contains__(object item) {
  772. return ((ICollection<object>)MakeTuple()).Contains(item);
  773. }
  774. #endregion
  775. private PythonTuple MakeTuple() {
  776. return PythonTuple.MakeTuple(
  777. st_mode,
  778. st_ino,
  779. st_dev,
  780. st_nlink,
  781. st_uid,
  782. st_gid,
  783. st_size,
  784. _atime,
  785. _mtime,
  786. _ctime
  787. );
  788. }
  789. #region Object overrides
  790. public override bool Equals(object obj) {
  791. if (obj is stat_result) {
  792. return MakeTuple().Equals(((stat_result)obj).MakeTuple());
  793. } else {
  794. return MakeTuple().Equals(obj);
  795. }
  796. }
  797. public override int GetHashCode() {
  798. return MakeTuple().GetHashCode();
  799. }
  800. #endregion
  801. #region IList<object> Members
  802. int IList<object>.IndexOf(object item) {
  803. return MakeTuple().IndexOf(item);
  804. }
  805. void IList<object>.Insert(int index, object item) {
  806. throw new InvalidOperationException();
  807. }
  808. void IList<object>.RemoveAt(int index) {
  809. throw new InvalidOperationException();
  810. }
  811. object IList<object>.this[int index] {
  812. get {
  813. return MakeTuple()[index];
  814. }
  815. set {
  816. throw new InvalidOperationException();
  817. }
  818. }
  819. #endregion
  820. #region ICollection<object> Members
  821. void ICollection<object>.Add(object item) {
  822. throw new InvalidOperationException();
  823. }
  824. void ICollection<object>.Clear() {
  825. throw new InvalidOperationException();
  826. }
  827. bool ICollection<object>.Contains(object item) {
  828. return __contains__(item);
  829. }
  830. void ICollection<object>.CopyTo(object[] array, int arrayIndex) {
  831. throw new NotImplementedException();
  832. }
  833. int ICollection<object>.Count {
  834. get { return __len__(); }
  835. }
  836. bool ICollection<object>.IsReadOnly {
  837. get { return true; }
  838. }
  839. bool ICollection<object>.Remove(object item) {
  840. throw new InvalidOperationException();
  841. }
  842. #endregion
  843. #region IEnumerable<object> Members
  844. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  845. foreach (object o in MakeTuple()) {
  846. yield return o;
  847. }
  848. }
  849. #endregion
  850. #region IEnumerable Members
  851. IEnumerator IEnumerable.GetEnumerator() {
  852. foreach (object o in MakeTuple()) {
  853. yield return o;
  854. }
  855. }
  856. #endregion
  857. #region IList Members
  858. int IList.Add(object value) {
  859. throw new InvalidOperationException();
  860. }
  861. void IList.Clear() {
  862. throw new InvalidOperationException();
  863. }
  864. bool IList.Contains(object value) {
  865. return __contains__(value);
  866. }
  867. int IList.IndexOf(object value) {
  868. return MakeTuple().IndexOf(value);
  869. }
  870. void IList.Insert(int index, object value) {
  871. throw new InvalidOperationException();
  872. }
  873. bool IList.IsFixedSize {
  874. get { return true; }
  875. }
  876. bool IList.IsReadOnly {
  877. get { return true; }
  878. }
  879. void IList.Remove(object value) {
  880. throw new InvalidOperationException();
  881. }
  882. void IList.RemoveAt(int index) {
  883. throw new InvalidOperationException();
  884. }
  885. object IList.this[int index] {
  886. get {
  887. return MakeTuple()[index];
  888. }
  889. set {
  890. throw new InvalidOperationException();
  891. }
  892. }
  893. #endregion
  894. #region ICollection Members
  895. void ICollection.CopyTo(Array array, int index) {
  896. throw new NotImplementedException();
  897. }
  898. int ICollection.Count {
  899. get { return __len__(); }
  900. }
  901. bool ICollection.IsSynchronized {
  902. get { return false; }
  903. }
  904. object ICollection.SyncRoot {
  905. get { return this; }
  906. }
  907. #endregion
  908. }
  909. private static bool HasExecutableExtension(string path) {
  910. string extension = Path.GetExtension(path).ToLower(CultureInfo.InvariantCulture);
  911. return (extension == ".exe" || extension == ".dll" || extension == ".com" || extension == ".bat");
  912. }
  913. [Documentation("stat(path) -> stat result\nGathers statistics about the specified file or directory")]
  914. public static object stat(string path) {
  915. if (path == null) throw PythonOps.TypeError("expected string, got NoneType");
  916. stat_result sr;
  917. try {
  918. FileInfo fi = new FileInfo(path);
  919. int mode = 0;
  920. long size;
  921. if (Directory.Exists(path)) {
  922. size = 0;
  923. mode = 0x4000 | S_IEXEC;
  924. } else if (File.Exists(path)) {
  925. size = fi.Length;
  926. mode = 0x8000;
  927. if (HasExecutableExtension(path)) {
  928. mode |= S_IEXEC;
  929. }
  930. } else {
  931. throw PythonExceptions.CreateThrowable(WindowsError, PythonExceptions._WindowsError.ERROR_PATH_NOT_FOUND, "file does not exist: " + path);
  932. }
  933. long st_atime = (long)PythonTime.TicksToTimestamp(fi.LastAccessTime.ToUniversalTime().Ticks);
  934. long st_ctime = (long)PythonTime.TicksToTimestamp(fi.CreationTime.ToUniversalTime().Ticks);
  935. long st_mtime = (long)PythonTime.TicksToTimestamp(fi.LastWriteTime.ToUniversalTime().Ticks);
  936. mode |= S_IREAD;
  937. if ((fi.Attributes & FileAttributes.ReadOnly) == 0) {
  938. mode |= S_IWRITE;
  939. }
  940. sr = new stat_result(mode, size, st_atime, st_mtime, st_ctime);
  941. } catch (ArgumentException) {
  942. throw PythonExceptions.CreateThrowable(WindowsError, PythonExceptions._WindowsError.ERROR_INVALID_NAME, "The path is invalid: " + path);
  943. } catch (Exception e) {
  944. throw ToPythonException(e, path);
  945. }
  946. return sr;
  947. }
  948. public static string strerror(int code) {
  949. switch(code) {
  950. case 0: return "No error";
  951. case PythonErrorNumber.E2BIG: return "Arg list too long";
  952. case PythonErrorNumber.EACCES: return "Permission denied";
  953. case PythonErrorNumber.EAGAIN: return "Resource temporarily unavailable";
  954. case PythonErrorNumber.EBADF: return "Bad file descriptor";
  955. case PythonErrorNumber.EBUSY: return "Resource device";
  956. case PythonErrorNumber.ECHILD: return "No child processes";
  957. case PythonErrorNumber.EDEADLK: return "Resource deadlock avoided";
  958. case PythonErrorNumber.EDOM: return "Domain error";
  959. case PythonErrorNumber.EDQUOT: return "Unknown error";
  960. case PythonErrorNumber.EEXIST: return "File exists";
  961. case PythonErrorNumber.EFAULT: return "Bad address";
  962. case PythonErrorNumber.EFBIG: return "File too large";
  963. case PythonErrorNumber.EILSEQ: return "Illegal byte sequence";
  964. case PythonErrorNumber.EINTR: return "Interrupted function call";
  965. case PythonErrorNumber.EINVAL: return "Invalid argument";
  966. case PythonErrorNumber.EIO: return "Input/output error";
  967. case PythonErrorNumber.EISCONN: return "Unknown error";
  968. case PythonErrorNumber.EISDIR: return "Is a directory";
  969. case PythonErrorNumber.EMFILE: return "Too many open files";
  970. case PythonErrorNumber.EMLINK: return "Too many links";
  971. case PythonErrorNumber.ENAMETOOLONG: return "Filename too long";
  972. case PythonErrorNumber.ENFILE: return "Too many open files in system";
  973. case PythonErrorNumber.ENODEV: return "No such device";
  974. case PythonErrorNumber.ENOENT: return "No such file or directory";
  975. case PythonErrorNumber.ENOEXEC: return "Exec format error";
  976. case PythonErrorNumber.ENOLCK: return "No locks available";
  977. case PythonErrorNumber.ENOMEM: return "Not enough space";
  978. case PythonErrorNumber.ENOSPC: return "No space left on device";
  979. case PythonErrorNumber.ENOSYS: return "Function not implemented";
  980. case PythonErrorNumber.ENOTDIR: return "Not a directory";
  981. case PythonErrorNumber.ENOTEMPTY: return "Directory not empty";
  982. case PythonErrorNumber.ENOTSOCK: return "Unknown error";
  983. case PythonErrorNumber.ENOTTY: return "Inappropriate I/O control operation";
  984. case PythonErrorNumber.ENXIO: return "No such device or address";
  985. case PythonErrorNumber.EPERM: return "Operation not permitted";
  986. case PythonErrorNumber.EPIPE: return "Broken pipe";
  987. case PythonErrorNumber.ERANGE: return "Result too large";
  988. case PythonErrorNumber.EROFS: return "Read-only file system";
  989. case PythonErrorNumber.ESPIPE: return "Invalid seek";
  990. case PythonErrorNumber.ESRCH: return "No such process";
  991. case PythonErrorNumber.EXDEV: return "Improper link";
  992. default:
  993. return "Unknown error " + code;
  994. }
  995. }
  996. private static PythonType WindowsError {
  997. get {
  998. #if !SILVERLIGHT
  999. return PythonExceptions.WindowsError;
  1000. #else
  1001. return PythonExceptions.OSError;
  1002. #endif
  1003. }
  1004. }
  1005. #if !SILVERLIGHT
  1006. [Documentation("system(command) -> int\nExecute the command (a string) in a subshell.")]
  1007. public static int system(string command) {
  1008. ProcessStartInfo psi = GetProcessInfo(command);
  1009. psi.CreateNoWindow = false;
  1010. try {
  1011. Process process = Process.Start(psi);
  1012. if (process == null) {
  1013. return -1;
  1014. }
  1015. process.WaitForExit();
  1016. return process.ExitCode;
  1017. } catch (Win32Exception) {
  1018. return 1;
  1019. }
  1020. }
  1021. public static string tempnam(CodeContext/*!*/ context) {
  1022. return tempnam(context, null);
  1023. }
  1024. public static string tempnam(CodeContext/*!*/ context, string dir) {
  1025. return tempnam(context, null, null);
  1026. }
  1027. public static string tempnam(CodeContext/*!*/ context, string dir, string prefix) {
  1028. PythonOps.Warn(context, PythonExceptions.RuntimeWarning, "tempnam is a potential security risk to your program");
  1029. try {
  1030. dir = Path.GetTempPath(); // Reasonably consistent with CPython behavior under Windows
  1031. return Path.GetFullPath(Path.Combine(dir, prefix ?? String.Empty) + Path.GetRandomFileName());
  1032. } catch (Exception e) {
  1033. throw ToPythonException(e, dir);
  1034. }
  1035. }
  1036. public static object times() {
  1037. System.Diagnostics.Process p = System.Diagnostics.Process.GetCurrentProcess();
  1038. return PythonTuple.MakeTuple(p.UserProcessorTime.TotalSeconds,
  1039. p.PrivilegedProcessorTime.TotalSeconds,
  1040. 0, // child process system time
  1041. 0, // child process os time
  1042. DateTime.Now.Subtract(p.StartTime).TotalSeconds);
  1043. }
  1044. #endif
  1045. #if !SILVERLIGHT
  1046. public static PythonFile/*!*/ tmpfile(CodeContext/*!*/ context) {
  1047. try {
  1048. FileStream sw = new FileStream(Path.GetTempFileName(), FileMode.Open, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
  1049. PythonFile res = PythonFile.Create(context, sw, sw.Name, "w+b");
  1050. return res;
  1051. } catch (Exception e) {
  1052. throw ToPythonException(e);
  1053. }
  1054. }
  1055. public static string/*!*/ tmpnam(CodeContext/*!*/ context) {
  1056. PythonOps.Warn(context, PythonExceptions.RuntimeWarning, "tmpnam is a potential security risk to your program");
  1057. return Path.GetFullPath(Path.GetTempPath() + Path.GetRandomFileName());
  1058. }
  1059. public static void unlink(string path) {
  1060. UnlinkWorker(path);
  1061. }
  1062. private static void UnlinkWorker(string path) {
  1063. if (path == null) {
  1064. throw new ArgumentNullException("path");
  1065. } else if (path.IndexOfAny(Path.GetInvalidPathChars()) != -1 || Path.GetFileName(path).IndexOfAny(Path.GetInvalidFileNameChars()) != -1) {
  1066. throw PythonExceptions.CreateThrowable(WindowsError, PythonExceptions._WindowsError.ERROR_INVALID_NAME, "The file could not be found for deletion: " + path);
  1067. } else if (!File.Exists(path)) {
  1068. throw PythonExceptions.CreateThrowable(WindowsError, PythonExceptions._WindowsError.ERROR_FILE_NOT_FOUND, "The file could not be found for deletion: " + path);
  1069. }
  1070. try {
  1071. File.Delete(path);
  1072. } catch (Exception e) {
  1073. throw ToPythonException(e, path);
  1074. }
  1075. }
  1076. public static void unsetenv(string varname) {
  1077. System.Environment.SetEnvironmentVariable(varname, null);
  1078. }
  1079. #endif
  1080. public static object urandom(int n) {
  1081. RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
  1082. byte[] data = new byte[n];
  1083. rng.GetBytes(data);
  1084. return PythonBinaryReader.PackDataIntoString(data, n);
  1085. }
  1086. private static readonly object _umaskKey = new object();
  1087. public static int umask(CodeContext/*!*/ context, int mask) {
  1088. mask &= 0x180;
  1089. object oldMask = PythonContext.GetContext(context).GetSetModuleState(_umaskKey, mask);
  1090. if (oldMask == null) {
  1091. return 0;
  1092. } else {
  1093. return (int)oldMask;
  1094. }
  1095. }
  1096. #if !SILVERLIGHT
  1097. public static void utime(string path, PythonTuple times) {
  1098. try {
  1099. FileInfo fi = new FileInfo(path);
  1100. if (times == null) {
  1101. fi.LastAccessTime = DateTime.Now;
  1102. fi.LastWriteTime = DateTime.Now;
  1103. } else if (times.__len__() == 2) {
  1104. DateTime atime = new DateTime(PythonTime.TimestampToTicks(Converter.ConvertToDouble(times[0])), DateTimeKind.Utc);
  1105. DateTime mtime = new DateTime(PythonTime.TimestampToTicks(Converter.ConvertToDouble(times[1])), DateTimeKind.Utc);
  1106. fi.LastAccessTime = atime;
  1107. fi.LastWriteTime = mtime;
  1108. } else {
  1109. throw PythonOps.TypeError("times value must be a 2-value tuple (atime, mtime)");
  1110. }
  1111. } catch (Exception e) {
  1112. throw ToPythonException(e, path);
  1113. }
  1114. }
  1115. public static PythonTuple waitpid(int pid, object options) {
  1116. Process process;
  1117. lock (_processToIdMapping) {
  1118. if (!_processToIdMapping.TryGetValue(pid, out process)) {
  1119. throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, PythonErrorNumber.ECHILD, "No child processes");
  1120. }
  1121. }
  1122. process.WaitForExit();
  1123. PythonTuple res = PythonTuple.MakeTuple(pid, process.ExitCode);
  1124. lock (_processToIdMapping) {
  1125. // lower 3 bits are user defined and ignored (matching NT's handle semantics)
  1126. _processToIdMapping.Remove(pid & ~0x03);
  1127. _freeProcessIds.Add(pid & ~0x03);
  1128. }
  1129. return res;
  1130. }
  1131. #endif
  1132. public static void write(CodeContext/*!*/ context, int fd, string text) {
  1133. try {
  1134. PythonContext pythonContext = PythonContext.GetContext(context);
  1135. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  1136. pf.write(text);
  1137. } catch (Exception e) {
  1138. throw ToPythonException(e);
  1139. }
  1140. }
  1141. public const int O_APPEND = 0x8;
  1142. public const int O_CREAT = 0x100;
  1143. public const int O_TRUNC = 0x200;
  1144. public const int O_EXCL = 0x400;
  1145. public const int O_NOINHERIT = 0x80;
  1146. public const int O_RANDOM = 0x10;
  1147. public const int O_SEQUENTIAL = 0x20;
  1148. public const int O_SHORT_LIVED = 0x1000;
  1149. public const int O_TEMPORARY = 0x40;
  1150. public const int O_WRONLY = 0x1;
  1151. public const int O_RDONLY = 0x0;
  1152. public const int O_RDWR = 0x2;
  1153. public const int O_BINARY = 0x8000;
  1154. public const int O_TEXT = 0x4000;
  1155. public const int P_WAIT = 0;
  1156. public const int P_NOWAIT = 1;
  1157. public const int P_NOWAITO = 3;
  1158. // Not used by IronPython
  1159. public const int P_OVERLAY = 2;
  1160. public const int P_DETACH = 4;
  1161. public const int TMP_MAX = 32767;
  1162. #endregion
  1163. #region Private implementation details
  1164. private static Exception ToPythonException(Exception e) {
  1165. return ToPythonException(e, null);
  1166. }
  1167. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Interoperability", "CA1404:CallGetLastErrorImmediatelyAfterPInvoke")]
  1168. private static Exception ToPythonException(Exception e, string filename) {
  1169. if (e is ArgumentException || e is ArgumentNullException || e is ArgumentTypeException) {
  1170. // rethrow reasonable exceptions
  1171. return ExceptionHelpers.UpdateForRethrow(e);
  1172. }
  1173. #if !SILVERLIGHT
  1174. int error = Marshal.GetLastWin32Error();
  1175. #endif
  1176. string message = e.Message;
  1177. int errorCode;
  1178. bool isWindowsError = false;
  1179. Win32Exception winExcep = e as Win32Exception;
  1180. if (winExcep != null) {
  1181. errorCode = winExcep.NativeErrorCode;
  1182. message = GetFormattedException(e, errorCode);
  1183. isWindowsError = true;
  1184. } else {
  1185. UnauthorizedAccessException unauth = e as UnauthorizedAccessException;
  1186. if (unauth != null) {
  1187. isWindowsError = true;
  1188. errorCode = PythonExceptions._WindowsError.ERROR_ACCESS_DENIED;
  1189. if (filename != null) {
  1190. message = string.Format("Access is denied: '{0}'", filename);
  1191. } else {
  1192. message = "Access is denied";
  1193. }
  1194. }
  1195. #if !SILVERLIGHT
  1196. IOException ioe = e as IOException;
  1197. if (ioe != null) {
  1198. switch (error) {
  1199. case PythonExceptions._WindowsError.ERROR_DIR_NOT_EMPTY:
  1200. throw PythonExceptions.CreateThrowable(WindowsError, error, "The directory is not empty");
  1201. case PythonExceptions._WindowsError.ERROR_ACCESS_DENIED:
  1202. throw PythonExceptions.CreateThrowable(WindowsError, error, "Access is denied");
  1203. case PythonExceptions._WindowsError.ERROR_SHARING_VIOLATION:
  1204. throw PythonExceptions.CreateThrowable(WindowsError, error, "The process cannot access the file because it is being used by another process");
  1205. }
  1206. }
  1207. #endif
  1208. errorCode = System.Runtime.InteropServices.Marshal.GetHRForException(e);
  1209. if ((errorCode & ~0xfff) == (unchecked((int)0x80070000))) {
  1210. // Win32 HR, translate HR to Python error code if possible, otherwise
  1211. // report the HR.
  1212. errorCode = errorCode & 0xfff;
  1213. message = GetFormattedException(e, errorCode);
  1214. isWindowsError = true;
  1215. }
  1216. }
  1217. if (isWindowsError) {
  1218. return PythonExceptions.CreateThrowable(WindowsError, errorCode, message);
  1219. }
  1220. return PythonExceptions.CreateThrowable(PythonExceptions.OSError, errorCode, message);
  1221. }
  1222. private static string GetFormattedException(Exception e, int hr) {
  1223. return "[Errno " + hr.ToString() + "] " + e.Message;
  1224. }
  1225. // Win32 error codes
  1226. private const int S_IWRITE = 0x80 + 0x10 + 0x02; // owner / group / world
  1227. private const int S_IREAD = 0x100 + 0x20 + 0x04; // owner / group / world
  1228. private const int S_IEXEC = 0x40 + 0x08 + 0x01; // owner / group / world
  1229. public const int F_OK = 0;
  1230. public const int X_OK = 1;
  1231. public const int W_OK = 2;
  1232. public const int R_OK = 4;
  1233. private static void addBase(string[] files, List ret) {
  1234. foreach (string file in files) {
  1235. ret.AddNoLock(Path.GetFileName(file));
  1236. }
  1237. }
  1238. private static FileMode FileModeFromFlags(int flags) {
  1239. if ((flags & O_APPEND) != 0) return FileMode.Append;
  1240. if ((flags & O_EXCL) != 0) {
  1241. if ((flags & O_CREAT) != 0) {
  1242. return FileMode.CreateNew;
  1243. }
  1244. return FileMode.Open;
  1245. }
  1246. if ((flags & O_CREAT) != 0) return FileMode.Create;
  1247. if ((flags & O_TRUNC) != 0) return FileMode.Truncate;
  1248. return FileMode.Open;
  1249. }
  1250. private static FileAccess FileAccessFromFlags(int flags) {
  1251. if ((flags & O_RDWR) != 0) return FileAccess.ReadWrite;
  1252. if ((flags & O_WRONLY) != 0) return FileAccess.Write;
  1253. return FileAccess.Read;
  1254. }
  1255. #if !SILVERLIGHT // Processes
  1256. [PythonType]
  1257. private class POpenFile : PythonFile {
  1258. private Process _process;
  1259. internal POpenFile(CodeContext/*!*/ context, string command, Process process, Stream stream, string mode)
  1260. : base(PythonContext.GetContext(context)) {
  1261. __init__(stream, PythonContext.GetContext(context).DefaultEncoding, command, mode);
  1262. this._process = process;
  1263. }
  1264. public override object close() {
  1265. base.close();
  1266. if (_process.HasExited && _process.ExitCode != 0) {
  1267. return _process.ExitCode;
  1268. }
  1269. return null;
  1270. }
  1271. }
  1272. private static ProcessStartInfo GetProcessInfo(string command) {
  1273. // TODO: always run through cmd.exe ?
  1274. command = command.Trim();
  1275. string baseCommand, args;
  1276. if (!TryGetExecutableCommand(command, out baseCommand, out args)) {
  1277. if (!TryGetShellCommand(command, out baseCommand, out args)) {
  1278. throw PythonOps.WindowsError("The system can not find command '{0}'", command);
  1279. }
  1280. }
  1281. ProcessStartInfo psi = new ProcessStartInfo(baseCommand, args);
  1282. psi.UseShellExecute = false;
  1283. return psi;
  1284. }
  1285. private static bool TryGetExecutableCommand(string command, out string baseCommand, out string args) {
  1286. baseCommand = command;
  1287. args = String.Empty;
  1288. int pos;
  1289. if (command[0] == '\"') {
  1290. for (pos = 1; pos < command.Length; pos++) {
  1291. if (command[pos] == '\"') {
  1292. baseCommand = command.Substring(1, pos - 1).Trim();
  1293. if (pos + 1 < command.Length) {
  1294. args = command.Substring(pos + 1);
  1295. }
  1296. break;
  1297. }
  1298. }
  1299. if (pos == command.Length) {
  1300. baseCommand = command.Substring(1).Trim();
  1301. command = command + "\"";
  1302. }
  1303. } else {
  1304. pos = command.IndexOf(' ');
  1305. if (pos != -1) {
  1306. baseCommand = command.Substring(0, pos);
  1307. // pos won't be the last one
  1308. args = command.Substring(pos + 1);
  1309. }
  1310. }
  1311. string fullpath = Path.GetFullPath(baseCommand);
  1312. if (File.Exists(fullpath)) {
  1313. baseCommand = fullpath;
  1314. return true;
  1315. }
  1316. // TODO: need revisit
  1317. string sysdir = System.Environment.GetFolderPath(System.Environment.SpecialFolder.System);
  1318. foreach (string suffix in new string[] { string.Empty, ".com", ".exe", "cmd", ".bat" }) {
  1319. fullpath = Path.Combine(sysdir, baseCommand + suffix);
  1320. if (File.Exists(fullpath)) {
  1321. baseCommand = fullpath;
  1322. return true;
  1323. }
  1324. }
  1325. return false;
  1326. }
  1327. private static bool TryGetShellCommand(string command, out string baseCommand, out string args) {
  1328. baseCommand = Environment.GetEnvironmentVariable("COMSPEC");
  1329. args = String.Empty;
  1330. if (baseCommand == null) {
  1331. baseCommand = Environment.GetEnvironmentVariable("SHELL");
  1332. if (baseCommand == null) {
  1333. return false;
  1334. }
  1335. args = String.Format("-c \"{0}\"", command);
  1336. } else {
  1337. args = String.Format("/c {0}", command);
  1338. }
  1339. return true;
  1340. }
  1341. private static Exception DirectoryExists() {
  1342. return PythonExceptions.CreateThrowable(WindowsError, PythonExceptions._WindowsError.ERROR_ALREADY_EXISTS, "directory already exists");
  1343. }
  1344. #endif
  1345. #endregion
  1346. }
  1347. }