/Languages/IronPython/IronPython.Modules/nt.cs
C# | 1866 lines | 1449 code | 301 blank | 116 comment | 269 complexity | 5d49ee9affc6c622e73809bd99dbec5b MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
Large files files are truncated, but you can click here to view the full file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Diagnostics;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Runtime.InteropServices;
- using System.Security.Cryptography;
- using Microsoft.Scripting;
- using Microsoft.Scripting.Runtime;
- using Microsoft.Scripting.Utils;
- using IronPython.Runtime;
- using IronPython.Runtime.Exceptions;
- using IronPython.Runtime.Operations;
- using IronPython.Runtime.Types;
- #if FEATURE_NUMERICS
- using System.Numerics;
- #else
- using Microsoft.Scripting.Math;
- #endif
- #if NETCOREAPP1_0
- using Environment = System.FakeEnvironment;
- #endif
- [assembly: PythonModule("nt", typeof(IronPython.Modules.PythonNT))]
- namespace IronPython.Modules {
- public static class PythonNT {
- public const string __doc__ = "Provides low-level operationg system access for files, the environment, etc...";
- #if FEATURE_PROCESS
- private static Dictionary<int, Process> _processToIdMapping = new Dictionary<int, Process>();
- private static List<int> _freeProcessIds = new List<int>();
- private static int _processCount;
- #endif
- #region Public API Surface
- #if FEATURE_PROCESS
- public static void abort() {
- System.Environment.FailFast("IronPython os.abort");
- }
- #endif
- /// <summary>
- /// Checks for the specific permissions, provided by the mode parameter, are available for the provided path. Permissions can be:
- ///
- /// F_OK: Check to see if the file exists
- /// R_OK | W_OK | X_OK: Check for the specific permissions. Only W_OK is respected.
- /// </summary>
- public static bool access(CodeContext/*!*/ context, string path, int mode) {
- if (path == null) throw PythonOps.TypeError("expected string, got None");
- #if FEATURE_FILESYSTEM
- try {
- FileAttributes fa = File.GetAttributes(path);
- if (mode == F_OK) {
- return true;
- }
- // match the behavior of the VC C Runtime
- if ((fa & FileAttributes.Directory) != 0) {
- // directories have read & write access
- return true;
- }
- if ((fa & FileAttributes.ReadOnly) != 0 && (mode & W_OK) != 0) {
- // want to write but file is read-only
- return false;
- }
- return true;
- } catch(ArgumentException) {
- } catch(PathTooLongException) {
- } catch(NotSupportedException) {
- } catch(FileNotFoundException) {
- } catch(DirectoryNotFoundException) {
- } catch(IOException) {
- } catch(UnauthorizedAccessException) {
- }
- return false;
- #else
- throw new NotImplementedException();
- #endif
- }
- #if FEATURE_FILESYSTEM
- public static void chdir([NotNull]string path) {
- if (String.IsNullOrEmpty(path)) {
- throw PythonExceptions.CreateThrowable(WindowsError, PythonExceptions._WindowsError.ERROR_INVALID_NAME, "Path cannot be an empty string");
- }
- try {
- Directory.SetCurrentDirectory(path);
- } catch (Exception e) {
- throw ToPythonException(e, path);
- }
- }
- public static void chmod(string path, int mode) {
- try {
- FileInfo fi = new FileInfo(path);
- if ((mode & S_IWRITE) != 0) {
- fi.Attributes &= ~(FileAttributes.ReadOnly);
- } else {
- fi.Attributes |= FileAttributes.ReadOnly;
- }
- } catch (Exception e) {
- throw ToPythonException(e, path);
- }
- }
- #endif
- public static void close(CodeContext/*!*/ context, int fd) {
- PythonContext pythonContext = PythonContext.GetContext(context);
- PythonFileManager fileManager = pythonContext.FileManager;
- PythonFile file;
- if (fileManager.TryGetFileFromId(pythonContext, fd, out file)) {
- fileManager.CloseIfLast(fd, file);
- } else {
- Stream stream = fileManager.GetObjectFromId(fd) as Stream;
- if (stream == null) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 9, "Bad file descriptor");
- }
- fileManager.CloseIfLast(fd, stream);
- }
- }
- public static void closerange(CodeContext/*!*/ context, int fd_low, int fd_high) {
- for (var fd = fd_low; fd <= fd_high; fd++) {
- try {
- close(context, fd);
- } catch (OSException) {
- // ignore errors on close
- }
- }
- }
- private static bool IsValidFd(CodeContext/*!*/ context, int fd) {
- PythonContext pythonContext = PythonContext.GetContext(context);
- PythonFile file;
- if (pythonContext.FileManager.TryGetFileFromId(pythonContext, fd, out file)) {
- return true;
- }
- Object o;
- if (pythonContext.FileManager.TryGetObjectFromId(pythonContext, fd, out o)) {
- var stream = o as Stream;
- if (stream != null) {
- return true;
- }
- }
- return false;
- }
- public static int dup(CodeContext/*!*/ context, int fd) {
- PythonContext pythonContext = PythonContext.GetContext(context);
- PythonFile file;
- if (pythonContext.FileManager.TryGetFileFromId(pythonContext, fd, out file)) {
- return pythonContext.FileManager.AddToStrongMapping(file);
- } else {
- Stream stream = pythonContext.FileManager.GetObjectFromId(fd) as Stream;
- if (stream == null) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 9, "Bad file descriptor");
- }
- return pythonContext.FileManager.AddToStrongMapping(stream);
- }
- }
- public static int dup2(CodeContext/*!*/ context, int fd, int fd2) {
- PythonContext pythonContext = PythonContext.GetContext(context);
- PythonFile file;
- if (!IsValidFd(context, fd)) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 9, "Bad file descriptor");
- }
- if (! pythonContext.FileManager.ValidateFdRange(fd2)) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 9, "Bad file descriptor");
- }
- bool fd2Valid = IsValidFd(context, fd2);
- if (fd == fd2) {
- if (fd2Valid) {
- return fd2;
- }
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 9, "Bad file descriptor");
- }
- if (fd2Valid) {
- close(context, fd2);
- }
- if (pythonContext.FileManager.TryGetFileFromId(pythonContext, fd, out file)) {
- return pythonContext.FileManager.AddToStrongMapping(file, fd2);
- }
- var stream = pythonContext.FileManager.GetObjectFromId(fd) as Stream;
- if (stream == null) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 9, "Bad file descriptor");
- }
- return pythonContext.FileManager.AddToStrongMapping(stream, fd2);
- }
-
- #if FEATURE_PROCESS
- /// <summary>
- /// single instance of environment dictionary is shared between multiple runtimes because the environment
- /// is shared by multiple runtimes.
- /// </summary>
- public static readonly object environ = new PythonDictionary(new EnvironmentDictionaryStorage());
- #endif
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
- public static readonly PythonType error = Builtin.OSError;
- public static void _exit(CodeContext/*!*/ context, int code) {
- PythonContext.GetContext(context).DomainManager.Platform.TerminateScriptExecution(code);
- }
- public static object fdopen(CodeContext/*!*/ context, int fd) {
- return fdopen(context, fd, "r");
- }
- public static object fdopen(CodeContext/*!*/ context, int fd, string mode) {
- return fdopen(context, fd, mode, 0);
- }
- public static object fdopen(CodeContext/*!*/ context, int fd, string mode, int bufsize) {
- // check for a valid file mode...
- PythonFile.ValidateMode(mode);
- PythonContext pythonContext = PythonContext.GetContext(context);
- PythonFile pf;
- if (pythonContext.FileManager.TryGetFileFromId(pythonContext, fd, out pf)) {
- return pf;
- }
- Stream stream = pythonContext.FileManager.GetObjectFromId(fd) as Stream;
- if (stream == null) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 9, "Bad file descriptor");
- }
- return PythonFile.Create(context, stream, stream.ToString(), mode);
- }
- [LightThrowing]
- public static object fstat(CodeContext/*!*/ context, int fd) {
- PythonContext pythonContext = PythonContext.GetContext(context);
- PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
- if (pf.IsConsole) {
- return new stat_result(8192);
- }
- return lstat(pf.name);
- }
- public static void fsync(CodeContext context, int fd) {
- PythonContext pythonContext = PythonContext.GetContext(context);
- PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
- if (!pf.IsOutput) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 9, "Bad file descriptor");
- }
- try {
- pf.FlushToDisk();
- } catch (Exception ex) {
- if (ex is ValueErrorException ||
- ex is IOException) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 9, "Bad file descriptor");
- }
- throw;
- }
- }
- public static string getcwd(CodeContext/*!*/ context) {
- return context.LanguageContext.DomainManager.Platform.CurrentDirectory;
- }
- public static string getcwdu(CodeContext/*!*/ context) {
- return context.LanguageContext.DomainManager.Platform.CurrentDirectory;
- }
- public static string _getfullpathname(CodeContext/*!*/ context, [NotNull]string/*!*/ dir) {
- PlatformAdaptationLayer pal = context.LanguageContext.DomainManager.Platform;
- try {
- return pal.GetFullPath(dir);
- } catch (ArgumentException) {
- // .NET validates the path, CPython doesn't... so we replace invalid chars with
- // Char.Maxvalue, get the full path, and then replace the Char.Maxvalue's back w/
- // their original value.
- string newdir = dir;
-
- if (IsWindows()) {
- if (newdir.Length >= 2 && newdir[1] == ':' &&
- (newdir[0] < 'a' || newdir[0] > 'z') && (newdir[0] < 'A' || newdir[0] > 'Z')) {
- // invalid drive, .NET will reject this
- if (newdir.Length == 2) {
- return newdir + Path.DirectorySeparatorChar;
- } else if (newdir[2] == Path.DirectorySeparatorChar) {
- return newdir;
- } else {
- return newdir.Substring(0, 2) + Path.DirectorySeparatorChar + newdir.Substring(2);
- }
- }
- if (newdir.Length > 2 && newdir.IndexOf(':', 2) != -1) {
- // : is an invalid char if it's not in the 2nd position
- newdir = newdir.Substring(0, 2) + newdir.Substring(2).Replace(':', Char.MaxValue);
- }
- if (newdir.Length > 0 && newdir[0] == ':') {
- newdir = Char.MaxValue + newdir.Substring(1);
- }
- }
- foreach (char c in Path.GetInvalidPathChars()) {
- newdir = newdir.Replace(c, Char.MaxValue);
- }
-
- // walk backwards through the path replacing the same characters. We should have
- // only updated the directory leaving the filename which we're fixing.
- string res = pal.GetFullPath(newdir);
- int curDir = dir.Length;
- for (int curRes = res.Length - 1; curRes >= 0; curRes--) {
- if (res[curRes] == Char.MaxValue) {
- for (curDir--; curDir >= 0; curDir--) {
- if (newdir[curDir] == Char.MaxValue) {
- res = res.Substring(0, curRes) + dir[curDir] + res.Substring(curRes + 1);
- break;
- }
- }
- }
- }
- return res;
- }
- }
- private static bool IsWindows() {
- return Environment.OSVersion.Platform == PlatformID.Win32NT ||
- Environment.OSVersion.Platform == PlatformID.Win32S ||
- Environment.OSVersion.Platform == PlatformID.Win32Windows;
- }
- #if FEATURE_PROCESS
- public static int getpid() {
- return System.Diagnostics.Process.GetCurrentProcess().Id;
- }
- #endif
- public static List listdir(CodeContext/*!*/ context, [NotNull]string path) {
- if (path == String.Empty) {
- throw PythonOps.WindowsError("The system cannot find the path specified: '{0}'", path);
- }
- List ret = PythonOps.MakeList();
- try {
- addBase(context.LanguageContext.DomainManager.Platform.GetFileSystemEntries(path, "*"), ret);
- return ret;
- } catch (Exception e) {
- throw ToPythonException(e, path);
- }
- }
- public static void lseek(CodeContext context, int filedes, long offset, int whence) {
- PythonFile file = context.LanguageContext.FileManager.GetFileFromId(context.LanguageContext, filedes);
- file.seek(offset, whence);
- }
- /// <summary>
- /// lstat(path) -> stat result
- /// Like stat(path), but do not follow symbolic links.
- /// </summary>
- [LightThrowing]
- public static object lstat([BytesConversion]string path) {
- // TODO: detect links
- return stat(path);
- }
- #if FEATURE_UNIX && FEATURE_NATIVE
- [DllImport("libc")]
- private static extern int symlink(string source, string dest);
- public static void symlink(CodeContext context, string source, string link_name) {
- int result = symlink(source, link_name);
- if(result != 0) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, 0, source, link_name);
- }
- }
- #endif
- #if FEATURE_FILESYSTEM
- public static void mkdir(string path) {
- if (Directory.Exists(path))
- throw DirectoryExists();
- try {
- Directory.CreateDirectory(path);
- } catch (Exception e) {
- throw ToPythonException(e, path);
- }
- }
- public static void mkdir(string path, int mode) {
- if (Directory.Exists(path)) throw DirectoryExists();
- // we ignore mode
- try {
- Directory.CreateDirectory(path);
- } catch (Exception e) {
- throw ToPythonException(e, path);
- }
- }
- public static object open(CodeContext/*!*/ context, string filename, int flag) {
- return open(context, filename, flag, 0777);
- }
- private const int DefaultBufferSize = 4096;
- public static object open(CodeContext/*!*/ context, string filename, int flag, int mode) {
- try {
- FileMode fileMode = FileModeFromFlags(flag);
- FileAccess access = FileAccessFromFlags(flag);
- FileOptions options = FileOptionsFromFlags(flag);
- Stream fs;
- if (Environment.OSVersion.Platform == PlatformID.Win32NT && (String.Compare(filename, "nul", true) == 0)) {
- fs = Stream.Null;
- } else if (access == FileAccess.Read && (fileMode == FileMode.CreateNew || fileMode == FileMode.Create || fileMode == FileMode.Append)) {
- // .NET doesn't allow Create/CreateNew w/ access == Read, so create the file, then close it, then
- // open it again w/ just read access.
- fs = new FileStream(filename, fileMode, FileAccess.Write, FileShare.None);
- fs.Dispose();
- fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, DefaultBufferSize, options);
- } else if (access == FileAccess.ReadWrite && fileMode == FileMode.Append) {
- fs = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.ReadWrite, DefaultBufferSize, options);
- } else {
- fs = new FileStream(filename, fileMode, access, FileShare.ReadWrite, DefaultBufferSize, options);
- }
-
- string mode2;
- if (fs.CanRead && fs.CanWrite) mode2 = "w+";
- else if (fs.CanWrite) mode2 = "w";
- else mode2 = "r";
- if ((flag & O_BINARY) != 0) {
- mode2 += "b";
- }
- return PythonContext.GetContext(context).FileManager.AddToStrongMapping(PythonFile.Create(context, fs, filename, mode2));
- } catch (Exception e) {
- throw ToPythonException(e, filename);
- }
- }
- private static FileOptions FileOptionsFromFlags(int flag) {
- FileOptions res = FileOptions.None;
- if ((flag & O_TEMPORARY) != 0) {
- res |= FileOptions.DeleteOnClose;
- }
- if ((flag & O_RANDOM) != 0) {
- res |= FileOptions.RandomAccess;
- }
- if ((flag & O_SEQUENTIAL) != 0) {
- res |= FileOptions.SequentialScan;
- }
- return res;
- }
- #endif
- #if FEATURE_PIPES
- public static PythonTuple pipe(CodeContext context) {
- return PythonFile.CreatePipeAsFd(context);
- }
- #endif
- #if FEATURE_PROCESS
- public static PythonFile popen(CodeContext/*!*/ context, string command) {
- return popen(context, command, "r");
- }
- public static PythonFile popen(CodeContext/*!*/ context, string command, string mode) {
- return popen(context, command, mode, 4096);
- }
- public static PythonFile popen(CodeContext/*!*/ context, string command, string mode, int bufsize) {
- if (String.IsNullOrEmpty(mode)) mode = "r";
- ProcessStartInfo psi = GetProcessInfo(command, true);
- psi.CreateNoWindow = true; // ipyw shouldn't create a new console window
- Process p;
- PythonFile res;
- try {
- switch (mode) {
- case "r":
- psi.RedirectStandardOutput = true;
- p = Process.Start(psi);
- res = new POpenFile(context, command, p, p.StandardOutput.BaseStream, "r");
- break;
- case "w":
- psi.RedirectStandardInput = true;
- p = Process.Start(psi);
- res = new POpenFile(context, command, p, p.StandardInput.BaseStream, "w");
- break;
- default:
- throw PythonOps.ValueError("expected 'r' or 'w' for mode, got {0}", mode);
- }
- } catch (Exception e) {
- throw ToPythonException(e);
- }
- return res;
- }
- public static PythonTuple popen2(CodeContext/*!*/ context, string command) {
- return popen2(context, command, "t");
- }
- public static PythonTuple popen2(CodeContext/*!*/ context, string command, string mode) {
- return popen2(context, command, "t", 4096);
- }
- public static PythonTuple popen2(CodeContext/*!*/ context, string command, string mode, int bufsize) {
- if (String.IsNullOrEmpty(mode)) mode = "t";
- if (mode != "t" && mode != "b") throw PythonOps.ValueError("mode must be 't' or 'b' (default is t)");
- if (mode == "t") mode = String.Empty;
- try {
- ProcessStartInfo psi = GetProcessInfo(command, true);
- psi.RedirectStandardInput = true;
- psi.RedirectStandardOutput = true;
- psi.CreateNoWindow = true; // ipyw shouldn't create a new console window
- Process p = Process.Start(psi);
- return PythonTuple.MakeTuple(new POpenFile(context, command, p, p.StandardInput.BaseStream, "w" + mode),
- new POpenFile(context, command, p, p.StandardOutput.BaseStream, "r" + mode));
- } catch (Exception e) {
- throw ToPythonException(e);
- }
- }
- public static PythonTuple popen3(CodeContext/*!*/ context, string command) {
- return popen3(context, command, "t");
- }
- public static PythonTuple popen3(CodeContext/*!*/ context, string command, string mode) {
- return popen3(context, command, "t", 4096);
- }
- public static PythonTuple popen3(CodeContext/*!*/ context, string command, string mode, int bufsize) {
- if (String.IsNullOrEmpty(mode)) mode = "t";
- if (mode != "t" && mode != "b") throw PythonOps.ValueError("mode must be 't' or 'b' (default is t)");
- if (mode == "t") mode = String.Empty;
- try {
- ProcessStartInfo psi = GetProcessInfo(command, true);
- psi.RedirectStandardInput = true;
- psi.RedirectStandardOutput = true;
- psi.RedirectStandardError = true;
- psi.CreateNoWindow = true; // ipyw shouldn't create a new console window
- Process p = Process.Start(psi);
- return PythonTuple.MakeTuple(new POpenFile(context, command, p, p.StandardInput.BaseStream, "w" + mode),
- new POpenFile(context, command, p, p.StandardOutput.BaseStream, "r" + mode),
- new POpenFile(context, command, p, p.StandardError.BaseStream, "r+" + mode));
- } catch (Exception e) {
- throw ToPythonException(e);
- }
- }
- public static void putenv(string varname, string value) {
- try {
- System.Environment.SetEnvironmentVariable(varname, value);
- } catch (Exception e) {
- throw ToPythonException(e);
- }
- }
- #endif
- public static string read(CodeContext/*!*/ context, int fd, int buffersize) {
- if (buffersize < 0) {
- throw PythonExceptions.CreateThrowable(PythonExceptions.OSError, PythonErrorNumber.EINVAL, "Invalid argument");
- }
- try {
- PythonContext pythonContext = PythonContext.GetContext(context);
- PythonFile pf = pythonContext.FileManager.GetFileFromId(pythonContext, fd);
- return pf.read(buffersize);
- } catch (Exception e) {
- throw ToPythonException(e);
- }
- }
- public static void rename(string src, string dst) {
- try {
- Directory.Move(src, dst);
- } catch (Exception e) {
- throw ToPythonException(e);
- }
- }
- public static void rmdir(string path) {
- try {
- Directory.Delete(path);
- } catch (Exception e) {
- throw ToPythonException(e, path);
- }
- }
- #if FEATURE_PROCESS
- /// <summary>
- /// spawns a new process.
- ///
- /// If mode is nt.P_WAIT then then the call blocks until the process exits and the return value
- /// is the exit code.
- ///
- /// Otherwise the call returns a handle to the process. The caller must then call nt.waitpid(pid, options)
- /// to free the handle and get the exit code of the process. Failure to call nt.waitpid will result
- /// in a handle leak.
- /// </summary>
- public static object spawnl(CodeContext/*!*/ context, int mode, string path, params object[] args) {
- return SpawnProcessImpl(context, MakeProcess(), mode, path, args);
- }
- /// <summary>
- /// spawns a new process.
- ///
- /// If mode is nt.P_WAIT then then the call blocks until the process exits and the return value
- /// is the exit code.
- ///
- /// Otherwise the call returns a handle to the process. The caller must then call nt.waitpid(pid, options)
- /// to free the handle and get the exit code of the process. Failure to call nt.waitpid will result
- /// in a handle leak.
- /// </summary>
- public static object spawnle(CodeContext/*!*/ context, int mode, string path, params object[] args) {
- if (args.Length < 1) {
- throw PythonOps.TypeError("spawnle() takes at least three arguments ({0} given)", 2 + args.Length);
- }
- object env = args[args.Length - 1];
- object[] slicedArgs = ArrayUtils.RemoveFirst(args);
- Process process = MakeProcess();
- #if NETSTANDARD
- SetEnvironment(process.StartInfo.Environment, env);
- #else
- SetEnvironment(process.StartInfo.EnvironmentVariables, env);
- #endif
- return SpawnProcessImpl(context, process, mode, path, slicedArgs);
- }
- /// <summary>
- /// spawns a new process.
- ///
- /// If mode is nt.P_WAIT then then the call blocks until the process exits and the return value
- /// is the exit code.
- ///
- /// Otherwise the call returns a handle to the process. The caller must then call nt.waitpid(pid, options)
- /// to free the handle and get the exit code of the process. Failure to call nt.waitpid will result
- /// in a handle leak.
- /// </summary>
- public static object spawnv(CodeContext/*!*/ context, int mode, string path, object args) {
- return SpawnProcessImpl(context, MakeProcess(), mode, path, args);
- }
- /// <summary>
- /// spawns a new process.
- ///
- /// If mode is nt.P_WAIT then then the call blocks until the process exits and the return value
- /// is the exit code.
- ///
- /// Otherwise the call returns a handle to the process. The caller must then call nt.waitpid(pid, options)
- /// to free the handle and get the exit code of the process. Failure to call nt.waitpid will result
- /// in a handle leak.
- /// </summary>
- public static object spawnve(CodeContext/*!*/ context, int mode, string path, object args, object env) {
- Process process = MakeProcess();
- #if NETSTANDARD
- SetEnvironment(process.StartInfo.Environment, env);
- #else
- SetEnvironment(process.StartInfo.EnvironmentVariables, env);
- #endif
- return SpawnProcessImpl(context, process, mode, path, args);
- }
- private static Process MakeProcess() {
- try {
- return new Process();
- } catch (Exception e) {
- throw ToPythonException(e);
- }
- }
- private static object SpawnProcessImpl(CodeContext/*!*/ context, Process process, int mode, string path, object args) {
- try {
- process.StartInfo.Arguments = ArgumentsToString(context, args);
- process.StartInfo.FileName = path;
- process.StartInfo.UseShellExecute = false;
- } catch (Exception e) {
- throw ToPythonException(e, path);
- }
- if (!process.Start()) {
- throw PythonOps.OSError("Cannot start process: {0}", path);
- }
- if (mode == P_WAIT) {
- process.WaitForExit();
- int exitCode = process.ExitCode;
- process.Dispose();
- return exitCode;
- }
- lock (_processToIdMapping) {
- int id;
- if (_freeProcessIds.Count > 0) {
- id = _freeProcessIds[_freeProcessIds.Count - 1];
- _freeProcessIds.RemoveAt(_freeProcessIds.Count - 1);
- } else {
- // process IDs are handles on CPython/Win32 so we match
- // that behavior and return something that is handle like. Handles
- // on NT are guaranteed to have the low 2 bits not set and users
- // could use these for their own purposes. We therefore match that
- // behavior here.
- _processCount += 4;
- id = _processCount;
- }
- _processToIdMapping[id] = process;
- return ScriptingRuntimeHelpers.Int32ToObject(id);
- }
- }
- /// <summary>
- /// Copy elements from a Python mapping of dict environment variables to a StringDictionary.
- /// </summary>
- #if NETSTANDARD
- private static void SetEnvironment(IDictionary<string, string> currentEnvironment, object newEnvironment) {
- #else
- private static void SetEnvironment(System.Collections.Specialized.StringDictionary currentEnvironment, object newEnvironment) {
- #endif
- PythonDictionary env = newEnvironment as PythonDictionary;
- if (env == null) {
- throw PythonOps.TypeError("env argument must be a dict");
- }
- currentEnvironment.Clear();
- string strKey, strValue;
- foreach (object key in env.keys()) {
- if (!Converter.TryConvertToString(key, out strKey)) {
- throw PythonOps.TypeError("env dict contains a non-string key");
- }
- if (!Converter.TryConvertToString(env[key], out strValue)) {
- throw PythonOps.TypeError("env dict contains a non-string value");
- }
- currentEnvironment[strKey] = strValue;
- }
- }
- #endif
- /// <summary>
- /// Convert a sequence of args to a string suitable for using to spawn a process.
- /// </summary>
- private static string ArgumentsToString(CodeContext/*!*/ context, object args) {
- IEnumerator argsEnumerator;
- System.Text.StringBuilder sb = null;
- if (!PythonOps.TryGetEnumerator(context, args, out argsEnumerator)) {
- throw PythonOps.TypeError("args parameter must be sequence, not {0}", DynamicHelpers.GetPythonType(args));
- }
- bool space = false;
- try {
- // skip the first element, which is the name of the command being run
- argsEnumerator.MoveNext();
- while (argsEnumerator.MoveNext()) {
- if (sb == null) sb = new System.Text.StringBuilder(); // lazy creation
- string strarg = PythonOps.ToString(argsEnumerator.Current);
- if (space) {
- sb.Append(' ');
- }
- if (strarg.IndexOf(' ') != -1) {
- sb.Append('"');
- // double quote any existing quotes
- sb.Append(strarg.Replace("\"", "\"\""));
- sb.Append('"');
- } else {
- sb.Append(strarg);
- }
- space = true;
- }
- } finally {
- IDisposable disposable = argsEnumerator as IDisposable;
- if (disposable != null) disposable.Dispose();
- }
- if (sb == null) return "";
- return sb.ToString();
- }
- #if FEATURE_PROCESS
- public static void startfile(string filename, [DefaultParameterValue("open")]string operation) {
- System.Diagnostics.Process process = new System.Diagnostics.Process();
- #if NETSTANDARD
- process.StartInfo.FileName = "cmd";
- process.StartInfo.Arguments = "/c " + filename;
- process.StartInfo.UseShellExecute = false;
- #else
- process.StartInfo.FileName = filename;
- process.StartInfo.UseShellExecute = true;
- process.StartInfo.Verb = operation;
- #endif
- try {
- #if NETSTANDARD
- if (!File.Exists(filename)) throw new Win32Exception("The system cannot find the file specified");
- #endif
- process.Start();
- } catch (Exception e) {
- throw ToPythonException(e, filename);
- }
- }
- #endif
- [PythonType, DontMapIEnumerableToIter]
- public class stat_result : IList, IList<object> {
- private readonly object _mode, _size, _atime, _mtime, _ctime, _st_atime, _st_mtime, _st_ctime, _ino, _dev, _nlink, _uid, _gid;
- public const int n_fields = 13;
- public const int n_sequence_fields = 10;
- public const int n_unnamed_fields = 3;
- internal stat_result(int mode) : this(mode, BigInteger.Zero, BigInteger.Zero, BigInteger.Zero, BigInteger.Zero) {
- _mode = mode;
- }
- internal stat_result(int mode, BigInteger size, BigInteger st_atime, BigInteger st_mtime, BigInteger st_ctime) {
- _mode = mode;
- _size = size;
- _st_atime = _atime = TryShrinkToInt(st_atime);
- _st_mtime = _mtime = TryShrinkToInt(st_mtime);
- _st_ctime = _ctime = TryShrinkToInt(st_ctime);
- _ino = _dev = _nlink = _uid = _gid = ScriptingRuntimeHelpers.Int32ToObject(0);
- }
- public stat_result(CodeContext/*!*/ context, IList statResult, [DefaultParameterValue(null)]PythonDictionary dict) {
- // dict is allowed by CPython's stat_result, but doesn't seem to do anything, so we ignore it here.
- if (statResult.Count < 10) {
- throw PythonOps.TypeError("stat_result() takes an at least 10-sequence ({0}-sequence given)", statResult.Count);
- }
- _mode = statResult[0];
- _ino = statResult[1];
- _dev = statResult[2];
- _nlink = statResult[3];
- _uid = statResult[4];
- _gid = statResult[5];
- _size = statResult[6];
- _atime = statResult[7];
- _mtime = statResult[8];
- _ctime = statResult[9];
- object dictTime;
- if (statResult.Count >= 11) {
- _st_atime = TryShrinkToInt(statResult[10]);
- } else if (TryGetDictValue(dict, "st_atime", out dictTime)) {
- _st_atime = dictTime;
- } else {
- _st_atime = TryShrinkToInt(_atime);
- }
- if (statResult.Count >= 12) {
- _st_mtime = TryShrinkToInt(statResult[11]);
- } else if (TryGetDictValue(dict, "st_mtime", out dictTime)) {
- _st_mtime = dictTime;
- } else {
- _st_mtime = TryShrinkToInt(_mtime);
- }
- if (statResult.Count >= 13) {
- _st_ctime = TryShrinkToInt(statResult[12]);
- } else if (TryGetDictValue(dict, "st_ctime", out dictTime)) {
- _st_ctime = dictTime;
- } else {
- _st_ctime = TryShrinkToInt(_ctime);
- }
- }
- private static bool TryGetDictValue(PythonDictionary dict, string name, out object dictTime) {
- if (dict != null && dict.TryGetValue(name, out dictTime)) {
- dictTime = TryShrinkToInt(dictTime);
- return true;
- }
- dictTime = null;
- return false;
- }
- private static object TryShrinkToInt(object value) {
- if (!(value is BigInteger)) {
- return value;
- }
-
- return BigIntegerOps.__int__((BigInteger)value);
- }
- public object st_atime {
- get {
- return _st_atime;
- }
- }
- public object st_ctime {
- get {
- return _st_ctime;
- }
- }
- public object st_mtime {
- get {
- return _st_mtime;
- }
- }
- public object st_dev {
- get {
- return TryShrinkToInt(_dev);
- }
- }
- public object st_gid {
- get {
- return _gid;
- }
- }
- public object st_ino {
- get {
- return _ino;
- }
- }
- public object st_mode {
- get {
- return TryShrinkToInt(_mode);
- }
- }
- public object st_nlink {
- get {
- return TryShrinkToInt(_nlink);
- }
- }
- public object st_size {
- get {
- return _size;
- }
- }
- public object st_uid {
- get {
- return _uid;
- }
- }
- public static PythonTuple operator +(stat_result stat, object tuple) {
- PythonTuple tupleObj = tuple as PythonTuple;
- if (tupleObj == null) {
- throw PythonOps.TypeError("can only concatenate tuple (not \"{0}\") to tuple", PythonTypeOps.GetName(tuple));
- }
- return stat.MakeTuple() + tupleObj;
- }
- public static bool operator >(stat_result stat, [NotNull]stat_result o) {
- return stat.MakeTuple() > PythonTuple.Make(o);
- }
- public static bool operator <(stat_result stat, [NotNull]stat_result o) {
- return stat.MakeTuple() < PythonTuple.Make(o);
- }
- public static bool operator >=(stat_result stat, [NotNull]stat_result o) {
- return stat.MakeTuple() >= PythonTuple.Make(o);
- }
- public static bool operator <=(stat_result stat, [NotNull]stat_result o) {
- return stat.MakeTuple() <= PythonTuple.Make(o);
- }
- public static bool operator >(stat_result stat, object o) {
- return true;
- }
- public static bool operator <(stat_result stat, object o) {
- return false;
- }
- public static bool operator >=(stat_result stat, object o) {
- return true;
- }
- public static bool operator <=(stat_result stat, object o) {
- return false;
- }
- public static PythonTuple operator *(stat_result stat, int size) {
- return stat.MakeTuple() * size;
- }
- public static PythonTuple operator *(int size, stat_result stat) {
- return stat.MakeTuple() * size;
- }
- public override string ToString() {
- return string.Format("nt.stat_result("
- + "st_mode={0}, "
- + "st_ino={1}, "
- + "st_dev={2}, "
- + "st_nlink={3}, "
- + "st_uid={4}, "
- + "st_gid={5}, "
- + "st_size={6}, "
- + "st_atime={7}, "
- + "st_mtime={8}, "
- + "st_ctime={9})", MakeTuple().ToArray());
- }
- public string/*!*/ __repr__() {
- return ToString();
- }
- public PythonTuple __reduce__() {
- PythonDictionary timeDict = new PythonDictionary(3);
- timeDict["st_atime"] = st_atime;
- timeDict["st_ctime"] = st_ctime;
- timeDict["st_mtime"] = st_mtime;
- return PythonTuple.MakeTuple(
- DynamicHelpers.GetPythonTypeFromType(typeof(stat_result)),
- PythonTuple.MakeTuple(MakeTuple(), timeDict)
- );
- }
- #region ISequence Members
- //public object AddSequence(object other) {
- // return MakeTuple().AddSequence(other);
- //}
- //public object MultiplySequence(object count) {
- // return MakeTuple().MultiplySequence(count);
- //}
- public object this[int index] {
- get {
- return MakeTuple()[index];
- }
- }
- public object this[Slice slice] {
- get {
- return MakeTuple()[slice];
- }
- }
- public object __getslice__(int start, int stop) {
- return MakeTuple().__getslice__(start, stop);
- }
- public int __len__() {
- return MakeTuple().__len__();
- }
- public bool __contains__(object item) {
- return ((ICollection<object>)MakeTuple()).Contains(item);
- }
- #endregion
- private PythonTuple MakeTuple() {
- return PythonTuple.MakeTuple(
- st_mode,
- st_ino,
- st_dev,
- st_nlink,
- st_uid,
- st_gid,
- st_size,
- _atime,
- _mtime,
- _ctime
- );
- }
- #region Object overrides
- public override bool Equals(object obj) {
- if (obj is stat_result) {
- return MakeTuple().Equals(((stat_result)obj).MakeTuple());
- } else {
- return MakeTuple().Equals(obj);
- }
- }
- public override int GetHashCode() {
- return MakeTuple().GetHashCode();
- }
- #endregion
- #region IList<object> Members
- int IList<object>.IndexOf(object item) {
- return MakeTuple().IndexOf(item);
- }
- void IList<object>.Insert(int index, object item) {
- throw new InvalidOperationException();
- }
- void IList<object>.RemoveAt(int index) {
- throw new InvalidOperationException();
- }
- object IList<object>.this[int index] {
- get {
- return MakeTuple()[index];
- }
- set {
- throw new InvalidOperationException();
- }
- }
- #endregion
- #region ICollection<object> Members
- void ICollection<object>.Add(object item) {
- throw new InvalidOperationException();
- }
- void ICollection<object>.Clear() {
- throw new InvalidOperationException();
- }
- bool ICollection<object>.Contains(object item) {
- return __contains__(item);
- }
- void ICollection<object>.CopyTo(object[] array, int arrayIndex) {
- throw new NotImplementedException();
- }
- int ICollection<object>.Count {
- get { return __len__(); }
- }
- bool ICollection<object>.IsReadOnly {
- get { return true; }
- }
- bool ICollection<object>.Remove(object item) {
- throw new InvalidOperationException();
- }
- #endregion
- #region IEnumerable<object> Members
- IEnumerator<object> IEnumerable<object>.GetEnumerator() {
- foreach (object o in MakeTuple()) {
- yield return o;
- }
- }
- #endregion
- #region IEnumerable Members
- IEnumerator IEnumerable.GetEnumerator() {
- foreach (object o in MakeTuple()) {
- yield return o;
- }
- }
- #endregion
- #region IList Members
- int IList.Add(object value) {
- throw new InvalidOperationException();
- }
- void IList.Clear() {
- throw new InvalidOperationException();
- }
- bool IList.Contains(object value) {
- return __contains__(value);
- }
- int IList.IndexOf(object value) {
- return MakeTuple().IndexOf(value);
- }
- void IList.Insert(int index, object value) {
- throw new InvalidOperationException();
- }
- bool IList.IsFixedSize {
- get { return true; }
- }
- bool IList.IsReadOnly {
- get { return true; }
- }
- void IList.Remove(object value) {
- throw new InvalidOperationException();
- }
- void IList.RemoveAt(int index) {
- throw new InvalidOperationException();
- }
- object IList.this[int index] {
- get {
- return MakeTuple()[index];
- }
- set {
- throw new InvalidOperationException();
- }
- }
- #endregion
- #region ICollection Members
- void ICollection.CopyTo(Array array, int index) {
- throw new NotImplementedException();
- }
- int ICollection.Count {
- get { return __len__(); }
- }
- bool ICollection.IsSynchronized {
- get { return false; }
- }
- object ICollection.SyncRoot {
- get { return this; }
- }
- #endregion
- }
- private static bool HasExecutableExtension(string path) {
- string extension = Path.GetExtension(path).ToLowerInvariant();
- return (extension == ".exe" || extension == ".dll" || extension == ".com" || extension == ".bat");
- }
- [Documentation("stat(path) -> stat result\nGathers statistics about the specified file or directory")]
- [LightThrowing]
- public static object stat([BytesConversion]string path) {
- if (path == null) {
- return LightExceptions.Throw(PythonOps.TypeError("expected string, got NoneType"));
- }
- stat_result sr;
- try {
- FileInfo fi = new FileInfo(path);
- int mode = 0;
- long size;
- if (Directory.Exists(path)) {
- size = 0;
- mode = 0x4000 | S_IEXEC;
- } else if (File.Exists(path)) {
- size = fi.Length;
- mode = 0x8000;
- if (HasExecutableExtension(path)) {
- mode |= S_IEXEC;
- }
- } else {
- return LightExceptions.Throw(PythonExceptions.CreateThrowable(WindowsError, PythonExceptions._WindowsError.ERROR_PATH_NOT_FOUND, "file does not exist: " + path));
- }
- long st_atime = (long)PythonTime.TicksToTimestamp(fi.LastAccessTime.ToUniversalTime().Ticks);
- long st_ctime = (long)PythonTime.TicksToTimestamp(fi.CreationTime.ToUniversalTime().Ticks);
- long st_mtime = (long)PythonTime.TicksToTimestamp(fi.LastWriteTime.ToUniversalTime().Ticks);
- mode |= S_IREAD;
- if ((fi.Attributes & FileAttributes.ReadOnly) == 0) {
- mode |= S_IWRITE;
- }
- sr = new stat_result(mo…
Large files files are truncated, but you can click here to view the full file