PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/IronPython_2_0/Src/IronPython.Modules/nt.cs

#
C# | 1222 lines | 957 code | 203 blank | 62 comment | 162 complexity | e7ee776990e832a75b198c4a05b1ec77 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  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; using Microsoft;
  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.Math;
  26. using Microsoft.Scripting.Runtime;
  27. using Microsoft.Scripting.Utils;
  28. using IronPython.Runtime;
  29. using IronPython.Runtime.Exceptions;
  30. using IronPython.Runtime.Operations;
  31. using IronPython.Runtime.Types;
  32. [assembly: PythonModule("nt", typeof(IronPython.Modules.PythonNT))]
  33. namespace IronPython.Modules {
  34. public static class PythonNT {
  35. #region Public API Surface
  36. #if !SILVERLIGHT // FailFast
  37. public static void abort() {
  38. System.Environment.FailFast("IronPython os.abort");
  39. }
  40. #endif
  41. /// <summary>
  42. /// Checks for the specific permissions, provided by the mode parameter, are available for the provided path. Permissions can be:
  43. ///
  44. /// F_OK: Check to see if the file exists
  45. /// R_OK | W_OK | X_OK: Check for the specific permissions. Only W_OK is respected.
  46. /// </summary>
  47. public static bool access(CodeContext/*!*/ context, string path, int mode) {
  48. if (path == null) throw PythonOps.TypeError("expected string, got None");
  49. if (mode == F_OK) {
  50. return context.LanguageContext.DomainManager.Platform.FileExists(path);
  51. }
  52. #if !SILVERLIGHT
  53. // match the behavior of the VC C Runtime
  54. FileAttributes fa = File.GetAttributes(path);
  55. if ((fa & FileAttributes.Directory) != 0) {
  56. // directories have read & write access
  57. return true;
  58. }
  59. if ((fa & FileAttributes.ReadOnly) != 0 && (mode & W_OK) != 0) {
  60. // want to write but file is read-only
  61. return false;
  62. }
  63. return true;
  64. #else
  65. return false;
  66. #endif
  67. }
  68. #if !SILVERLIGHT // SetCurrentDirectory, FileInfo
  69. public static void chdir([NotNull]string path) {
  70. if (String.IsNullOrEmpty(path)) {
  71. throw PythonExceptions.CreateThrowable(WindowsError, PythonErrorNumber.EINVAL, "Path cannot be an empty string");
  72. }
  73. try {
  74. Directory.SetCurrentDirectory(path);
  75. } catch (Exception e) {
  76. throw ToPythonException(e);
  77. }
  78. }
  79. public static void chmod(string path, int mode) {
  80. FileInfo fi = new FileInfo(path);
  81. if ((mode & S_IWRITE) != 0) {
  82. fi.Attributes &= ~(FileAttributes.ReadOnly);
  83. } else {
  84. fi.Attributes |= FileAttributes.ReadOnly;
  85. }
  86. }
  87. #endif
  88. public static void close(CodeContext/*!*/ context, int fd) {
  89. PythonContext pythonContext = PythonContext.GetContext(context);
  90. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  91. pf.close();
  92. }
  93. #if !SILVERLIGHT
  94. /// <summary>
  95. /// single instance of environment dictionary is shared between multiple runtimes because the environment
  96. /// is shared by multiple runtimes.
  97. /// </summary>
  98. public static readonly object environ = new PythonDictionary(new EnvironmentDictionaryStorage());
  99. #endif
  100. public static readonly PythonType error = Builtin.OSError;
  101. public static void _exit(CodeContext/*!*/ context, int code) {
  102. PythonContext.GetContext(context).DomainManager.Platform.TerminateScriptExecution(code);
  103. }
  104. public static object fdopen(CodeContext/*!*/ context, int fd) {
  105. return fdopen(context, fd, "r");
  106. }
  107. public static object fdopen(CodeContext/*!*/ context, int fd, string mode) {
  108. return fdopen(context, fd, mode, 0);
  109. }
  110. public static object fdopen(CodeContext/*!*/ context, int fd, string mode, int bufsize) {
  111. // check for a valid file mode...
  112. PythonFile.ValidateMode(mode);
  113. PythonContext pythonContext = PythonContext.GetContext(context);
  114. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  115. return pf;
  116. }
  117. public static object fstat(CodeContext/*!*/ context, int fd) {
  118. PythonContext pythonContext = PythonContext.GetContext(context);
  119. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  120. if (pf.IsConsole) {
  121. return new stat_result(8192);
  122. }
  123. return lstat(pf.name);
  124. }
  125. public static string getcwd(CodeContext/*!*/ context) {
  126. return context.LanguageContext.DomainManager.Platform.CurrentDirectory;
  127. }
  128. public static string getcwdu(CodeContext/*!*/ context) {
  129. return context.LanguageContext.DomainManager.Platform.CurrentDirectory;
  130. }
  131. public static string _getfullpathname(CodeContext/*!*/ context, [NotNull]string/*!*/ dir) {
  132. PlatformAdaptationLayer pal = context.LanguageContext.DomainManager.Platform;
  133. try {
  134. return context.LanguageContext.DomainManager.Platform.GetFullPath(dir);
  135. } catch (ArgumentException) {
  136. // .NET validates the path, CPython doesn't... so we replace invalid chars with
  137. // Char.Maxvalue, get the full path, and then replace the Char.Maxvalue's back w/
  138. // their original value.
  139. string newdir = dir;
  140. foreach (char c in Path.GetInvalidPathChars()) {
  141. newdir = newdir.Replace(c, Char.MaxValue);
  142. }
  143. // walk backwards through the path replacing the same characters. We should have
  144. // only updated the directory leaving the filename which we're fixing.
  145. string res = context.LanguageContext.DomainManager.Platform.GetFullPath(newdir);
  146. int curDir = dir.Length;
  147. for (int curRes = res.Length - 1; curRes >= 0; curRes--) {
  148. if (res[curRes] == Char.MaxValue) {
  149. for (curDir--; curDir >= 0; curDir--) {
  150. if (newdir[curDir] == Char.MaxValue) {
  151. res = res.Substring(0, curRes) + dir[curDir] + res.Substring(curRes + 1);
  152. break;
  153. }
  154. }
  155. }
  156. }
  157. return res;
  158. }
  159. }
  160. #if !SILVERLIGHT
  161. public static int getpid() {
  162. return System.Diagnostics.Process.GetCurrentProcess().Id;
  163. }
  164. #endif
  165. public static List listdir(CodeContext/*!*/ context, string path) {
  166. List ret = PythonOps.MakeList();
  167. try {
  168. string[] files = context.LanguageContext.DomainManager.Platform.GetFiles(path, "*");
  169. addBase(files, ret);
  170. addBase(context.LanguageContext.DomainManager.Platform.GetDirectories(path, "*"), ret);
  171. return ret;
  172. } catch (Exception e) {
  173. throw ToPythonException(e);
  174. }
  175. }
  176. //
  177. // lstat(path) -> stat result
  178. // Like stat(path), but do not follow symbolic links.
  179. //
  180. public static object lstat(string path) {
  181. return stat(path);
  182. }
  183. #if !SILVERLIGHT
  184. public static void mkdir(string path) {
  185. if (Directory.Exists(path))
  186. throw DirectoryExists();
  187. try {
  188. Directory.CreateDirectory(path);
  189. } catch (Exception e) {
  190. throw ToPythonException(e);
  191. }
  192. }
  193. public static void mkdir(string path, int mode) {
  194. if (Directory.Exists(path)) throw DirectoryExists();
  195. // we ignore mode
  196. try {
  197. Directory.CreateDirectory(path);
  198. } catch (Exception e) {
  199. throw ToPythonException(e);
  200. }
  201. }
  202. #endif
  203. public static object open(CodeContext/*!*/ context, string filename, int flag) {
  204. return open(context, filename, flag, 0777);
  205. }
  206. public static object open(CodeContext/*!*/ context, string filename, int flag, int mode) {
  207. try {
  208. FileStream fs = File.Open(filename, FileModeFromFlags(flag), FileAccessFromFlags(flag), FileShare.ReadWrite);
  209. string mode2;
  210. if (fs.CanRead && fs.CanWrite) mode2 = "w+";
  211. else if (fs.CanWrite) mode2 = "w";
  212. else mode2 = "r";
  213. if ((flag & O_BINARY) != 0) {
  214. mode2 += "b";
  215. }
  216. return PythonContext.GetContext(context).FileManager.AddToStrongMapping(PythonFile.Create(context, fs, filename, mode2));
  217. } catch (Exception e) {
  218. throw ToPythonException(e);
  219. }
  220. }
  221. #if !SILVERLIGHT
  222. public static PythonFile popen(CodeContext/*!*/ context, string command) {
  223. return popen(context, command, "r");
  224. }
  225. public static PythonFile popen(CodeContext/*!*/ context, string command, string mode) {
  226. return popen(context, command, mode, 4096);
  227. }
  228. public static PythonFile popen(CodeContext/*!*/ context, string command, string mode, int bufsize) {
  229. if (String.IsNullOrEmpty(mode)) mode = "r";
  230. ProcessStartInfo psi = GetProcessInfo(command);
  231. psi.CreateNoWindow = true; // ipyw shouldn't create a new console window
  232. Process p;
  233. PythonFile res;
  234. try {
  235. switch (mode) {
  236. case "r":
  237. psi.RedirectStandardOutput = true;
  238. p = Process.Start(psi);
  239. res = new POpenFile(context, command, p, p.StandardOutput.BaseStream, "r");
  240. break;
  241. case "w":
  242. psi.RedirectStandardInput = true;
  243. p = Process.Start(psi);
  244. res = new POpenFile(context, command, p, p.StandardInput.BaseStream, "w");
  245. break;
  246. default:
  247. throw PythonOps.ValueError("expected 'r' or 'w' for mode, got {0}", mode);
  248. }
  249. } catch (Exception e) {
  250. throw ToPythonException(e);
  251. }
  252. return res;
  253. }
  254. public static PythonTuple popen2(CodeContext/*!*/ context, string command) {
  255. return popen2(context, command, "t");
  256. }
  257. public static PythonTuple popen2(CodeContext/*!*/ context, string command, string mode) {
  258. return popen2(context, command, "t", 4096);
  259. }
  260. public static PythonTuple popen2(CodeContext/*!*/ context, string command, string mode, int bufsize) {
  261. if (String.IsNullOrEmpty(mode)) mode = "t";
  262. if (mode != "t" && mode != "b") throw PythonOps.ValueError("mode must be 't' or 'b' (default is t)");
  263. if (mode == "t") mode = String.Empty;
  264. try {
  265. ProcessStartInfo psi = GetProcessInfo(command);
  266. psi.RedirectStandardInput = true;
  267. psi.RedirectStandardOutput = true;
  268. psi.CreateNoWindow = true; // ipyw shouldn't create a new console window
  269. Process p = Process.Start(psi);
  270. return PythonTuple.MakeTuple(new POpenFile(context, command, p, p.StandardInput.BaseStream, "w" + mode),
  271. new POpenFile(context, command, p, p.StandardOutput.BaseStream, "r" + mode));
  272. } catch (Exception e) {
  273. throw ToPythonException(e);
  274. }
  275. }
  276. public static PythonTuple popen3(CodeContext/*!*/ context, string command) {
  277. return popen3(context, command, "t");
  278. }
  279. public static PythonTuple popen3(CodeContext/*!*/ context, string command, string mode) {
  280. return popen3(context, command, "t", 4096);
  281. }
  282. public static PythonTuple popen3(CodeContext/*!*/ context, string command, string mode, int bufsize) {
  283. if (String.IsNullOrEmpty(mode)) mode = "t";
  284. if (mode != "t" && mode != "b") throw PythonOps.ValueError("mode must be 't' or 'b' (default is t)");
  285. if (mode == "t") mode = String.Empty;
  286. try {
  287. ProcessStartInfo psi = GetProcessInfo(command);
  288. psi.RedirectStandardInput = true;
  289. psi.RedirectStandardOutput = true;
  290. psi.RedirectStandardError = true;
  291. psi.CreateNoWindow = true; // ipyw shouldn't create a new console window
  292. Process p = Process.Start(psi);
  293. return PythonTuple.MakeTuple(new POpenFile(context, command, p, p.StandardInput.BaseStream, "w" + mode),
  294. new POpenFile(context, command, p, p.StandardOutput.BaseStream, "r" + mode),
  295. new POpenFile(context, command, p, p.StandardError.BaseStream, "r+" + mode));
  296. } catch (Exception e) {
  297. throw ToPythonException(e);
  298. }
  299. }
  300. public static void putenv(string varname, string value) {
  301. try {
  302. System.Environment.SetEnvironmentVariable(varname, value);
  303. } catch (Exception e) {
  304. throw ToPythonException(e);
  305. }
  306. }
  307. #endif
  308. public static string read(CodeContext/*!*/ context, int fd, int buffersize) {
  309. if (buffersize < 0) {
  310. throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, PythonErrorNumber.EINVAL, "Invalid argument");
  311. }
  312. try {
  313. PythonContext pythonContext = PythonContext.GetContext(context);
  314. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  315. return pf.read();
  316. } catch (Exception e) {
  317. throw ToPythonException(e);
  318. }
  319. }
  320. public static void remove(string path) {
  321. UnlinkWorker(path);
  322. }
  323. public static void rename(string src, string dst) {
  324. try {
  325. Directory.Move(src, dst);
  326. } catch (Exception e) {
  327. throw ToPythonException(e);
  328. }
  329. }
  330. public static void rmdir(string path) {
  331. try {
  332. Directory.Delete(path);
  333. } catch (Exception e) {
  334. throw ToPythonException(e);
  335. }
  336. }
  337. #if !SILVERLIGHT
  338. public static object spawnl(CodeContext/*!*/ context, int mode, string path, params object[] args) {
  339. return SpawnProcessImpl(context, MakeProcess(), mode, path, args);
  340. }
  341. public static object spawnle(CodeContext/*!*/ context, int mode, string path, params object[] args) {
  342. if (args.Length < 1) {
  343. throw PythonOps.TypeError("spawnle() takes at least three arguments ({0} given)", 2 + args.Length);
  344. }
  345. object env = args[args.Length - 1];
  346. object[] slicedArgs = ArrayUtils.RemoveFirst(args);
  347. Process process = MakeProcess();
  348. SetEnvironment(process.StartInfo.EnvironmentVariables, env);
  349. return SpawnProcessImpl(context, process, mode, path, slicedArgs);
  350. }
  351. public static object spawnv(CodeContext/*!*/ context, int mode, string path, object args) {
  352. return SpawnProcessImpl(context, MakeProcess(), mode, path, args);
  353. }
  354. public static object spawnve(CodeContext/*!*/ context, int mode, string path, object args, object env) {
  355. Process process = MakeProcess();
  356. SetEnvironment(process.StartInfo.EnvironmentVariables, env);
  357. return SpawnProcessImpl(context, process, mode, path, args);
  358. }
  359. private static Process MakeProcess() {
  360. try {
  361. return new Process();
  362. } catch (Exception e) {
  363. throw ToPythonException(e);
  364. }
  365. }
  366. private static object SpawnProcessImpl(CodeContext/*!*/ context, Process process, int mode, string path, object args) {
  367. try {
  368. process.StartInfo.Arguments = ArgumentsToString(context, args);
  369. process.StartInfo.FileName = path;
  370. process.StartInfo.UseShellExecute = false;
  371. } catch (Exception e) {
  372. throw ToPythonException(e);
  373. }
  374. if (!process.Start()) {
  375. throw PythonOps.OSError("Cannot start process: {0}", path);
  376. }
  377. if (mode == (int)P_WAIT) {
  378. process.WaitForExit();
  379. int exitCode = process.ExitCode;
  380. process.Close();
  381. return exitCode;
  382. } else {
  383. return process.Id;
  384. }
  385. }
  386. /// <summary>
  387. /// Copy elements from a Python mapping of dict environment variables to a StringDictionary.
  388. /// </summary>
  389. private static void SetEnvironment(System.Collections.Specialized.StringDictionary currentEnvironment, object newEnvironment) {
  390. PythonDictionary env = newEnvironment as PythonDictionary;
  391. if (env == null) {
  392. throw PythonOps.TypeError("env argument must be a dict");
  393. }
  394. currentEnvironment.Clear();
  395. string strKey, strValue;
  396. foreach (object key in env.keys()) {
  397. if (!Converter.TryConvertToString(key, out strKey)) {
  398. throw PythonOps.TypeError("env dict contains a non-string key");
  399. }
  400. if (!Converter.TryConvertToString(env[key], out strValue)) {
  401. throw PythonOps.TypeError("env dict contains a non-string value");
  402. }
  403. currentEnvironment[strKey] = strValue;
  404. }
  405. }
  406. #endif
  407. /// <summary>
  408. /// Convert a sequence of args to a string suitable for using to spawn a process.
  409. /// </summary>
  410. private static string ArgumentsToString(CodeContext/*!*/ context, object args) {
  411. IEnumerator argsEnumerator;
  412. System.Text.StringBuilder sb = null;
  413. if (!PythonOps.TryGetEnumerator(context, args, out argsEnumerator)) {
  414. throw PythonOps.TypeError("args parameter must be sequence, not {0}", DynamicHelpers.GetPythonType(args));
  415. }
  416. bool space = false;
  417. try {
  418. // skip the first element, which is the name of the command being run
  419. argsEnumerator.MoveNext();
  420. while (argsEnumerator.MoveNext()) {
  421. if (sb == null) sb = new System.Text.StringBuilder(); // lazy creation
  422. string strarg = PythonOps.ToString(argsEnumerator.Current);
  423. if (space) {
  424. sb.Append(' ');
  425. }
  426. if (strarg.IndexOf(' ') != -1) {
  427. sb.Append('"');
  428. sb.Append(strarg);
  429. sb.Append('"');
  430. } else {
  431. sb.Append(strarg);
  432. }
  433. space = true;
  434. }
  435. } finally {
  436. IDisposable disposable = argsEnumerator as IDisposable;
  437. if (disposable != null) disposable.Dispose();
  438. }
  439. if (sb == null) return "";
  440. return sb.ToString();
  441. }
  442. #if !SILVERLIGHT
  443. public static void startfile(string filename, [DefaultParameterValue("open")]string operation) {
  444. System.Diagnostics.Process process = new System.Diagnostics.Process();
  445. process.StartInfo.FileName = filename;
  446. process.StartInfo.UseShellExecute = true;
  447. process.StartInfo.Verb = operation;
  448. try {
  449. process.Start();
  450. } catch (Exception e) {
  451. throw ToPythonException(e);
  452. }
  453. }
  454. #endif
  455. [PythonType]
  456. public class stat_result : ISequence {
  457. private readonly object _mode, _size, _atime, _mtime, _ctime, _st_atime, _st_mtime, _st_ctime, _ino, _dev, _nlink, _uid, _gid;
  458. public const int n_fields = 13;
  459. public const int n_sequence_fields = 10;
  460. public const int n_unnamed_fields = 3;
  461. internal stat_result(int mode) : this(mode, BigInteger.Zero, BigInteger.Zero, BigInteger.Zero, BigInteger.Zero) {
  462. _mode = mode;
  463. }
  464. internal stat_result(int mode, BigInteger size, BigInteger st_atime, BigInteger st_mtime, BigInteger st_ctime) {
  465. _mode = mode;
  466. _size = size;
  467. _st_atime = _atime = TryShrinkToInt(st_atime);
  468. _st_mtime = _mtime = TryShrinkToInt(st_mtime);
  469. _st_ctime = _ctime = TryShrinkToInt(st_ctime);
  470. _ino = _dev = _nlink = _uid = _gid = RuntimeHelpers.Int32ToObject(0);
  471. }
  472. public stat_result(CodeContext/*!*/ context, ISequence statResult, [DefaultParameterValue(null)]PythonDictionary dict) {
  473. // dict is allowed by CPython's stat_result, but doesn't seem to do anything, so we ignore it here.
  474. if (statResult.__len__() < 10) {
  475. throw PythonOps.TypeError("stat_result() takes an at least 10-sequence ({0}-sequence given)", statResult.__len__());
  476. }
  477. _mode = statResult[0];
  478. _ino = statResult[1];
  479. _dev = statResult[2];
  480. _nlink = statResult[3];
  481. _uid = statResult[4];
  482. _gid = statResult[5];
  483. _size = statResult[6];
  484. _atime = statResult[7];
  485. _mtime = statResult[8];
  486. _ctime = statResult[9];
  487. object dictTime;
  488. if (statResult.__len__() >= 11) {
  489. _st_atime = TryShrinkToInt(statResult[10]);
  490. } else if (TryGetDictValue(dict, "st_atime", out dictTime)) {
  491. _st_atime = dictTime;
  492. } else {
  493. _st_atime = TryShrinkToInt(_atime);
  494. }
  495. if (statResult.__len__() >= 12) {
  496. _st_mtime = TryShrinkToInt(statResult[11]);
  497. } else if (TryGetDictValue(dict, "st_mtime", out dictTime)) {
  498. _st_mtime = dictTime;
  499. } else {
  500. _st_mtime = TryShrinkToInt(_mtime);
  501. }
  502. if (statResult.__len__() >= 13) {
  503. _st_ctime = TryShrinkToInt(statResult[12]);
  504. } else if (TryGetDictValue(dict, "st_ctime", out dictTime)) {
  505. _st_ctime = dictTime;
  506. } else {
  507. _st_ctime = TryShrinkToInt(_ctime);
  508. }
  509. }
  510. private static bool TryGetDictValue(PythonDictionary dict, string name, out object dictTime) {
  511. if (dict != null && dict.TryGetValue(name, out dictTime)) {
  512. dictTime = TryShrinkToInt(dictTime);
  513. return true;
  514. }
  515. dictTime = null;
  516. return false;
  517. }
  518. private static object TryShrinkToInt(object value) {
  519. BigInteger bi = value as BigInteger;
  520. if (Object.ReferenceEquals(bi, null)) {
  521. return value;
  522. }
  523. return BigIntegerOps.__int__(bi);
  524. }
  525. public object st_atime {
  526. get {
  527. return _st_atime;
  528. }
  529. }
  530. public object st_ctime {
  531. get {
  532. return _st_ctime;
  533. }
  534. }
  535. public object st_mtime {
  536. get {
  537. return _st_mtime;
  538. }
  539. }
  540. public object st_dev {
  541. get {
  542. return TryShrinkToInt(_dev);
  543. }
  544. }
  545. public object st_gid {
  546. get {
  547. return _gid;
  548. }
  549. }
  550. public object st_ino {
  551. get {
  552. return _ino;
  553. }
  554. }
  555. public object st_mode {
  556. get {
  557. return TryShrinkToInt(_mode);
  558. }
  559. }
  560. public object st_nlink {
  561. get {
  562. return TryShrinkToInt(_nlink);
  563. }
  564. }
  565. public object st_size {
  566. get {
  567. return _size;
  568. }
  569. }
  570. public object st_uid {
  571. get {
  572. return _uid;
  573. }
  574. }
  575. public override string ToString() {
  576. return MakeTuple().ToString();
  577. }
  578. public string/*!*/ __repr__() {
  579. return ToString();
  580. }
  581. public PythonTuple __reduce__() {
  582. PythonDictionary timeDict = new PythonDictionary(3);
  583. timeDict["st_atime"] = st_atime;
  584. timeDict["st_ctime"] = st_ctime;
  585. timeDict["st_mtime"] = st_mtime;
  586. return PythonTuple.MakeTuple(
  587. DynamicHelpers.GetPythonTypeFromType(typeof(stat_result)),
  588. PythonTuple.MakeTuple(MakeTuple(), timeDict)
  589. );
  590. }
  591. #region ISequence Members
  592. //public object AddSequence(object other) {
  593. // return MakeTuple().AddSequence(other);
  594. //}
  595. //public object MultiplySequence(object count) {
  596. // return MakeTuple().MultiplySequence(count);
  597. //}
  598. public object this[int index] {
  599. get {
  600. return MakeTuple()[index];
  601. }
  602. }
  603. public object this[Slice slice] {
  604. get {
  605. return MakeTuple()[slice];
  606. }
  607. }
  608. public object __getslice__(int start, int stop) {
  609. return MakeTuple().__getslice__(start, stop);
  610. }
  611. public int __len__() {
  612. return MakeTuple().__len__();
  613. }
  614. public bool __contains__(object item) {
  615. return ((ICollection<object>)MakeTuple()).Contains(item);
  616. }
  617. #endregion
  618. private PythonTuple MakeTuple() {
  619. return PythonTuple.MakeTuple(
  620. st_mode,
  621. st_ino,
  622. st_dev,
  623. st_nlink,
  624. st_uid,
  625. st_gid,
  626. st_size,
  627. _atime,
  628. _mtime,
  629. _ctime
  630. );
  631. }
  632. #region Object overrides
  633. public override bool Equals(object obj) {
  634. if (obj is stat_result) {
  635. return MakeTuple().Equals(((stat_result)obj).MakeTuple());
  636. } else {
  637. return MakeTuple().Equals(obj);
  638. }
  639. }
  640. public override int GetHashCode() {
  641. return MakeTuple().GetHashCode();
  642. }
  643. #endregion
  644. }
  645. private static bool HasExecutableExtension(string path) {
  646. string extension = Path.GetExtension(path).ToLower(CultureInfo.InvariantCulture);
  647. return (extension == ".exe" || extension == ".dll" || extension == ".com" || extension == ".bat");
  648. }
  649. [Documentation("stat(path) -> stat result\nGathers statistics about the specified file or directory")]
  650. public static object stat(string path) {
  651. if (path == null) throw PythonOps.TypeError("expected string, got NoneType");
  652. stat_result sr;
  653. try {
  654. FileInfo fi = new FileInfo(path);
  655. int mode = 0;
  656. long size;
  657. if (Directory.Exists(path)) {
  658. size = 0;
  659. mode = 0x4000 | S_IEXEC;
  660. } else if (File.Exists(path)) {
  661. size = fi.Length;
  662. mode = 0x8000;
  663. if (HasExecutableExtension(path)) {
  664. mode |= S_IEXEC;
  665. }
  666. } else {
  667. throw PythonExceptions.CreateThrowable(WindowsError, PythonErrorNumber.ENOENT, "file does not exist: " + path);
  668. }
  669. long st_atime = (long)PythonTime.TicksToTimestamp(fi.LastAccessTime.ToUniversalTime().Ticks);
  670. long st_ctime = (long)PythonTime.TicksToTimestamp(fi.CreationTime.ToUniversalTime().Ticks);
  671. long st_mtime = (long)PythonTime.TicksToTimestamp(fi.LastWriteTime.ToUniversalTime().Ticks);
  672. mode |= S_IREAD;
  673. if ((fi.Attributes & FileAttributes.ReadOnly) == 0) {
  674. mode |= S_IWRITE;
  675. }
  676. sr = new stat_result(mode, size, st_atime, st_mtime, st_ctime);
  677. } catch (ArgumentException) {
  678. throw PythonExceptions.CreateThrowable(WindowsError, PythonErrorNumber.EINVAL, "The path is invalid: " + path);
  679. } catch (Exception e) {
  680. throw ToPythonException(e);
  681. }
  682. return sr;
  683. }
  684. private static PythonType WindowsError {
  685. get {
  686. #if !SILVERLIGHT
  687. return PythonExceptions.WindowsError;
  688. #else
  689. return PythonExceptions.OSError;
  690. #endif
  691. }
  692. }
  693. #if !SILVERLIGHT
  694. [Documentation("system(command) -> int\nExecute the command (a string) in a subshell.")]
  695. public static int system(string command) {
  696. ProcessStartInfo psi = GetProcessInfo(command);
  697. psi.CreateNoWindow = false;
  698. Process process = Process.Start(psi);
  699. if (process == null) {
  700. return -1;
  701. }
  702. process.WaitForExit();
  703. return process.ExitCode;
  704. }
  705. public static string tempnam(CodeContext/*!*/ context) {
  706. return tempnam(context, null);
  707. }
  708. public static string tempnam(CodeContext/*!*/ context, string dir) {
  709. return tempnam(context, null, null);
  710. }
  711. public static string tempnam(CodeContext/*!*/ context, string dir, string prefix) {
  712. PythonOps.Warn(context, PythonExceptions.RuntimeWarning, "tempnam is a potential security risk to your program");
  713. try {
  714. dir = Path.GetTempPath(); // Reasonably consistent with CPython behavior under Windows
  715. return Path.GetFullPath(Path.Combine(dir, prefix ?? String.Empty) + Path.GetRandomFileName());
  716. } catch (Exception e) {
  717. throw ToPythonException(e);
  718. }
  719. }
  720. public static object times() {
  721. System.Diagnostics.Process p = System.Diagnostics.Process.GetCurrentProcess();
  722. return PythonTuple.MakeTuple(p.UserProcessorTime.TotalSeconds,
  723. p.PrivilegedProcessorTime.TotalSeconds,
  724. 0, // child process system time
  725. 0, // child process os time
  726. DateTime.Now.Subtract(p.StartTime).TotalSeconds);
  727. }
  728. #endif
  729. #if !SILVERLIGHT
  730. public static PythonFile/*!*/ tmpfile(CodeContext/*!*/ context) {
  731. try {
  732. FileStream sw = new FileStream(Path.GetTempFileName(), FileMode.Open, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.DeleteOnClose);
  733. PythonFile res = PythonFile.Create(context, sw, sw.Name, "w+b");
  734. return res;
  735. } catch (Exception e) {
  736. throw ToPythonException(e);
  737. }
  738. }
  739. public static string/*!*/ tmpnam(CodeContext/*!*/ context) {
  740. PythonOps.Warn(context, PythonExceptions.RuntimeWarning, "tmpnam is a potential security risk to your program");
  741. return Path.GetFullPath(Path.GetTempPath() + Path.GetRandomFileName());
  742. }
  743. #endif
  744. public static void unlink(string path) {
  745. UnlinkWorker(path);
  746. }
  747. private static void UnlinkWorker(string path) {
  748. if (path == null) throw new ArgumentNullException("path");
  749. if (!File.Exists(path)) {
  750. throw PythonExceptions.CreateThrowable(WindowsError, PythonErrorNumber.ENOENT, "The file could not be found for deletion: " + path);
  751. }
  752. try {
  753. File.Delete(path);
  754. } catch (Exception e) {
  755. throw ToPythonException(e);
  756. }
  757. }
  758. #if !SILVERLIGHT
  759. public static void unsetenv(string varname) {
  760. System.Environment.SetEnvironmentVariable(varname, null);
  761. }
  762. #endif
  763. public static object urandom(int n) {
  764. RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
  765. byte[] data = new byte[n];
  766. rng.GetBytes(data);
  767. return PythonBinaryReader.PackDataIntoString(data, n);
  768. }
  769. private static readonly object _umaskKey = new object();
  770. public static int umask(CodeContext/*!*/ context, int mask) {
  771. mask &= 0x180;
  772. object oldMask = PythonContext.GetContext(context).GetSetModuleState(_umaskKey, mask);
  773. if (oldMask == null) {
  774. return 0;
  775. } else {
  776. return (int)oldMask;
  777. }
  778. }
  779. #if !SILVERLIGHT
  780. public static void utime(string path, PythonTuple times) {
  781. try {
  782. FileInfo fi = new FileInfo(path);
  783. if (times == null) {
  784. fi.LastAccessTime = DateTime.Now;
  785. fi.LastWriteTime = DateTime.Now;
  786. } else if (times.__len__() == 2) {
  787. DateTime atime = new DateTime(PythonTime.TimestampToTicks(Converter.ConvertToDouble(times[0])), DateTimeKind.Utc);
  788. DateTime mtime = new DateTime(PythonTime.TimestampToTicks(Converter.ConvertToDouble(times[1])), DateTimeKind.Utc);
  789. fi.LastAccessTime = atime;
  790. fi.LastWriteTime = mtime;
  791. } else {
  792. throw PythonOps.TypeError("times value must be a 2-value tuple (atime, mtime)");
  793. }
  794. } catch (Exception e) {
  795. throw ToPythonException(e);
  796. }
  797. }
  798. public static PythonTuple waitpid(int pid, object options) {
  799. System.Diagnostics.Process process = System.Diagnostics.Process.GetProcessById(pid);
  800. if (process == null) {
  801. throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, PythonErrorNumber.ECHILD, "Cannot find process " + pid);
  802. }
  803. process.WaitForExit();
  804. return PythonTuple.MakeTuple(pid, process.ExitCode);
  805. }
  806. #endif
  807. public static void write(CodeContext/*!*/ context, int fd, string text) {
  808. try {
  809. PythonContext pythonContext = PythonContext.GetContext(context);
  810. PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
  811. pf.write(text);
  812. } catch (Exception e) {
  813. throw ToPythonException(e);
  814. }
  815. }
  816. public const int O_APPEND = 0x8;
  817. public const int O_CREAT = 0x100;
  818. public const int O_TRUNC = 0x200;
  819. public const int O_EXCL = 0x400;
  820. public const int O_NOINHERIT = 0x80;
  821. public const int O_RANDOM = 0x10;
  822. public const int O_SEQUENTIAL = 0x20;
  823. public const int O_SHORT_LIVED = 0x1000;
  824. public const int O_TEMPORARY = 0x40;
  825. public const int O_WRONLY = 0x1;
  826. public const int O_RDONLY = 0x0;
  827. public const int O_RDWR = 0x2;
  828. public const int O_BINARY = 0x8000;
  829. public const int O_TEXT = 0x4000;
  830. public const int P_WAIT = 0;
  831. public const int P_NOWAIT = 1;
  832. public const int P_NOWAITO = 3;
  833. // Not implemented:
  834. // public static object P_OVERLAY = 2;
  835. // public static object P_DETACH = 4;
  836. #endregion
  837. #region Private implementation details
  838. private static Exception ToPythonException(Exception e) {
  839. if (e is ArgumentException || e is ArgumentNullException || e is ArgumentTypeException) {
  840. // rethrow reasonable exceptions
  841. return ExceptionHelpers.UpdateForRethrow(e);
  842. }
  843. string message = e.Message;
  844. int errorCode;
  845. #if !SILVERLIGHT
  846. bool isWindowsError = false;
  847. Win32Exception winExcep = e as Win32Exception;
  848. if (winExcep != null) {
  849. errorCode = ToPythonErrorCode(winExcep.NativeErrorCode);
  850. message = GetFormattedException(e, errorCode);
  851. isWindowsError = true;
  852. } else {
  853. #endif
  854. errorCode = System.Runtime.InteropServices.Marshal.GetHRForException(e);
  855. if ((errorCode & ~0xfff) == (unchecked((int)0x80070000))) {
  856. // Win32 HR, translate HR to Python error code if possible, otherwise
  857. // report the HR.
  858. errorCode = ToPythonErrorCode(errorCode & 0xfff);
  859. message = GetFormattedException(e, errorCode);
  860. #if !SILVERLIGHT
  861. isWindowsError = true;
  862. #endif
  863. }
  864. #if !SILVERLIGHT
  865. }
  866. if (isWindowsError) {
  867. return PythonExceptions.CreateThrowable(WindowsError, errorCode, message);
  868. }
  869. #endif
  870. return PythonExceptions.CreateThrowable(PythonExceptions.OSError, errorCode, message);
  871. }
  872. private static string GetFormattedException(Exception e, int hr) {
  873. return "[Errno " + hr.ToString() + "] " + e.Message;
  874. }
  875. private static int ToPythonErrorCode(int win32ErrorCode) {
  876. switch (win32ErrorCode) {
  877. case ERROR_FILE_EXISTS: return PythonErrorNumber.EEXIST;
  878. case ERROR_ACCESS_DENIED: return PythonErrorNumber.EACCES;
  879. case ERROR_DLL_NOT_FOUND:
  880. case ERROR_FILE_NOT_FOUND:
  881. case ERROR_PATH_NOT_FOUND: return PythonErrorNumber.ENOENT;
  882. case ERROR_CANCELLED: return PythonErrorNumber.EINTR;
  883. case ERROR_NOT_ENOUGH_MEMORY: return PythonErrorNumber.ENOMEM;
  884. case ERROR_SHARING_VIOLATION: return PythonErrorNumber.EBUSY;
  885. case ERROR_NO_ASSOCIATION: return PythonErrorNumber.EINVAL;
  886. }
  887. return win32ErrorCode;
  888. }
  889. // Win32 error codes
  890. private const int ERROR_FILE_EXISTS = 80;
  891. private const int ERROR_ACCESS_DENIED = 5; // Access to the specified file is denied.
  892. private const int ERROR_FILE_NOT_FOUND = 2; //The specified file was not found.
  893. private const int ERROR_PATH_NOT_FOUND = 3; // The specified path was not found.
  894. private const int ERROR_NO_ASSOCIATION = 1155; //There is no application associated with the given file name extension.
  895. private const int ERROR_DLL_NOT_FOUND = 1157; // One of the library files necessary to run the application can't be found.
  896. private const int ERROR_CANCELLED = 1223; // The function prompted the user for additional information, but the user canceled the request.
  897. private const int ERROR_NOT_ENOUGH_MEMORY = 8; // There is not enough memory to perform the specified action.
  898. private const int ERROR_SHARING_VIOLATION = 32; //A sharing violation occurred.
  899. private const int ERROR_ALREADY_EXISTS = 183;
  900. private const int S_IWRITE = 0x80 + 0x10 + 0x02; // owner / group / world
  901. private const int S_IREAD = 0x100 + 0x20 + 0x04; // owner / group / world
  902. private const int S_IEXEC = 0x40 + 0x08 + 0x01; // owner / group / world
  903. public const int F_OK = 0;
  904. public const int X_OK = 1;
  905. public const int W_OK = 2;
  906. public const int R_OK = 4;
  907. private static void addBase(string[] files, List ret) {
  908. foreach (string file in files) {
  909. ret.AddNoLock(Path.GetFileName(file));
  910. }
  911. }
  912. private static FileMode FileModeFromFlags(int flags) {
  913. if ((flags & O_APPEND) != 0) return FileMode.Append;
  914. if ((flags & O_CREAT) != 0) return FileMode.CreateNew;
  915. if ((flags & O_TRUNC) != 0) return FileMode.Truncate;
  916. return FileMode.Open;
  917. }
  918. private static FileAccess FileAccessFromFlags(int flags) {
  919. if ((flags & O_RDWR) != 0) return FileAccess.ReadWrite;
  920. if ((flags & O_WRONLY) != 0) return FileAccess.Write;
  921. return FileAccess.Read;
  922. }
  923. #if !SILVERLIGHT // Processes
  924. [PythonType]
  925. private class POpenFile : PythonFile {
  926. private Process _process;
  927. public static object __new__(CodeContext/*!*/ context, string command, Process process, Stream stream, string mode) {
  928. return new POpenFile(context, command, process, stream, mode);
  929. }
  930. internal POpenFile(CodeContext/*!*/ context, string command, Process process, Stream stream, string mode)
  931. : base(PythonContext.GetContext(context)) {
  932. __init__(stream, PythonContext.GetContext(context).DefaultEncoding, command, mode);
  933. this._process = process;
  934. }
  935. public override object close() {
  936. base.close();
  937. if (_process.HasExited && _process.ExitCode != 0) {
  938. return _process.ExitCode;
  939. }
  940. return null;
  941. }
  942. }
  943. private static ProcessStartInfo GetProcessInfo(string command) {
  944. // TODO: always run through cmd.exe ?
  945. command = command.Trim();
  946. string baseCommand, args;
  947. if (!TryGetExecutableCommand(command, out baseCommand, out args)) {
  948. if (!TryGetShellCommand(command, out baseCommand, out args)) {
  949. throw PythonOps.WindowsError("The system can not find command '{0}'", command);
  950. }
  951. }
  952. ProcessStartInfo psi = new ProcessStartInfo(baseCommand, args);
  953. psi.UseShellExecute = false;
  954. return psi;
  955. }
  956. private static bool TryGetExecutableCommand(string command, out string baseCommand, out string args) {
  957. baseCommand = command;
  958. args = String.Empty;
  959. int pos;
  960. if (command[0] == '\"') {
  961. for (pos = 1; pos < command.Length; pos++) {
  962. if (command[pos] == '\"') {
  963. baseCommand = command.Substring(1, pos - 1).Trim();
  964. if (pos + 1 < command.Length) {
  965. args = command.Substring(pos + 1);
  966. }
  967. break;
  968. }
  969. }
  970. if (pos == command.Length)
  971. throw PythonOps.ValueError("mismatch quote in command");
  972. } else {
  973. pos = command.IndexOf(' ');
  974. if (pos != -1) {
  975. baseCommand = command.Substring(0, pos);
  976. // pos won't be the last one
  977. args = command.Substring(pos + 1);
  978. }
  979. }
  980. string fullpath = Path.GetFullPath(baseCommand);
  981. if (File.Exists(fullpath)) {
  982. baseCommand = fullpath;
  983. return true;
  984. }
  985. // TODO: need revisit
  986. string sysdir = System.Environment.GetFolderPath(System.Environment.SpecialFolder.System);
  987. foreach (string suffix in new string[] { string.Empty, ".com", ".exe", "cmd", ".bat" }) {
  988. fullpath = Path.Combine(sysdir, baseCommand + suffix);
  989. if (File.Exists(fullpath)) {
  990. baseCommand = fullpath;
  991. return true;
  992. }
  993. }
  994. return false;
  995. }
  996. private static bool TryGetShellCommand(string command, out string baseCommand, out string args) {
  997. baseCommand = Environment.GetEnvironmentVariable("COMSPEC");
  998. args = String.Empty;
  999. if (baseCommand == null) {
  1000. baseCommand = Environment.GetEnvironmentVariable("SHELL");
  1001. if (baseCommand == null) {
  1002. return false;
  1003. }
  1004. args = String.Format("-c \"{0}\"", command);
  1005. } else {
  1006. args = String.Format("/c {0}", command);
  1007. }
  1008. return true;
  1009. }
  1010. private static Exception DirectoryExists() {
  1011. PythonExceptions._WindowsError err = new PythonExceptions._WindowsError();
  1012. err.__init__(ERROR_ALREADY_EXISTS, "directory already exists");
  1013. err.errno = PythonErrorNumber.EEXIST;
  1014. return PythonExceptions.ToClr(err);
  1015. }
  1016. #endif
  1017. #endregion
  1018. }
  1019. }