internal FileStreamContentProvider(PlatformAdaptationLayer pal, string path) { Assert.NotNull(pal, path); _path = path; _pal = new PALHolder(pal); }
private static void SetCurrentDirectory(PlatformAdaptationLayer/*!*/ pal, string/*!*/ dir) { try { // TODO: MRI calls Win32 API SetCurrentDirctory directly, while BCL normalizes the path first. pal.CurrentDirectory = dir; } catch (Exception e) { throw ToRubyException(e, dir, DirectoryOperation.ChangeDir); } }
/*!*/ public static IEnumerable<string> GetMatches(PlatformAdaptationLayer/*!*/ pal, string/*!*/ pattern, int flags) { if (pattern.Length == 0) { yield break; } bool noEscape = ((flags & Constants.FNM_NOESCAPE) != 0); string[] groups = UngroupGlobs(pattern, noEscape); if (groups.Length == 0) { yield break; } foreach (string group in groups) { GlobMatcher matcher = new GlobMatcher(pal, group, flags); foreach (string filename in matcher.DoGlob()) { yield return filename; } } }
private static void GetExecutable(PlatformAdaptationLayer/*!*/ pal, string/*!*/ command, out string executable, out string arguments) { command = command.Trim(' '); if (command.Length == 0) { throw RubyExceptions.CreateEINVAL(command); } // This seems to be quite complicated: // 1) If the first part of the command is a shell command (DIR, ECHO, ...) or // if the command contains unquoted <, > or | then // it uses ENV['COMSPEC'] to execute the command: %COMSPEC% /c "COMMAND" // 2) It looks for the shortest prefix of command that is separated by space from the rest of the command that is either // a) An absolute path to an executable file. // b) Try prepend paths from ENV['PATH'] // c) Try Environment.SpecialFolder.System. // d) Try SHGetFolderPath(CSIDL_WINDOWS) - we can't get this from Environment.SpecialFolder, so we need to use // ENV["SystemRoot"] environment variable. // In each step it tries to append ".exe" or ".com" extension if the path doesn't exist. // // For example, if the command is `x/a b/x` and the directory structure is // x\a b\x.exe // x\a.exe // it executes a.exe. // // MRI probably calls CreateProcess Win32 API with lpApplicationName it resolves as described above and // lpCommandLine == command. System.Diagnostics.Process also uses this API with lpApplicationName == NULL and // lpCommandLine == '"{ProcessStartInfo.FileName}" {ProcessStartInfo.Arguments}'. // // Although CreateProcess does all the searching for an executable if passed no lpApplicationName, // we need to do it ourselves because it is slightly different in MRI (is that a bug?) and also because System.Diagnostics.Process // quotes the FileName :( // string comspec = pal.GetEnvironmentVariable("COMSPEC"); if (!pal.FileExists(comspec)) { comspec = null; } if (comspec != null && IndexOfUnquotedSpecialCharacter(command) >= 0) { executable = comspec; arguments = "/c \"" + command + "\""; return; } int start = 0; while (true) { int next = command.IndexOf(' ', start); executable = (next >= 0) ? command.Substring(0, next) : command; arguments = (next >= 0) ? command.Substring(next + 1) : ""; if (start == 0 && comspec != null && IsShellCommand(executable)) { executable = comspec; arguments = "/c \"" + command + "\""; return; } try { foreach (var path in GetExecutableFiles(pal, executable)) { if (pal.FileExists(path)) { // We need to set the path we found as executable. Althought makes command line of the target process // different from when called by MRI it will execute the right process. If we passed the original executable name // CreateProcess might resolve it to a different executable. executable = path; return; } } } catch (Exception e) { if (next < 0) { throw RubyExceptions.CreateENOENT(command, e); } } if (next < 0) { throw RubyExceptions.CreateENOENT(command); } start = next + 1; while (start < command.Length && command[start] == ' ') { start++; } } }
private static IEnumerable<string>/*!*/ GetAbsolutePaths(PlatformAdaptationLayer/*!*/ pal, string/*!*/ path) { if (pal.IsAbsolutePath(path)) { yield return path; } else { yield return pal.GetFullPath(path); string var = pal.GetEnvironmentVariable("PATH"); if (!String.IsNullOrEmpty(var)) { foreach (var prefix in var.Split(Path.PathSeparator)) { if (prefix.Length > 0) { yield return Path.Combine(prefix, path); } } } var = Environment.GetFolderPath(Environment.SpecialFolder.System); if (!String.IsNullOrEmpty(var)) { yield return Path.Combine(var, path); } var = pal.GetEnvironmentVariable("SystemRoot"); if (!String.IsNullOrEmpty(var)) { yield return Path.Combine(var, path); } } }
private static IEnumerable<string>/*!*/ GetExecutableFiles(PlatformAdaptationLayer/*!*/ pal, string/*!*/ path) { if (path[0] == '"' || path[path.Length - 1] == '"') { if (path.Length >= 3 && path[0] == '"' && path[path.Length - 1] == '"') { path = path.Substring(1, path.Length - 2); } else { yield break; } } string extension = Path.GetExtension(path); bool hasExtension = !String.IsNullOrEmpty(extension); bool isExecutable = hasExtension && Array.IndexOf(_ExecutableExtensions, extension.ToLowerInvariant()) >= 0; if (!hasExtension || isExecutable) { foreach (var fullPath in GetAbsolutePaths(pal, path)) { if (hasExtension) { yield return fullPath; } else { foreach (var ext in _ExecutableExtensions) { yield return fullPath + ext; } } } } }
internal PALHolder(PlatformAdaptationLayer pal) { _pal = pal; }
private static Stream OpenFile(CodeContext context, PlatformAdaptationLayer pal, string name, FileMode fileMode, FileAccess fileAccess, FileShare fileShare) { try { return pal.OpenInputFileStream(name, fileMode, fileAccess, fileShare); } catch (UnauthorizedAccessException e) { throw PythonFile.ToIoException(context, name, e); } catch (IOException e) { PythonFile.AddFilename(context, name, e); throw e; } }
internal GlobMatcher(PlatformAdaptationLayer/*!*/ pal, string/*!*/ pattern, int flags) { _pal = pal; _pattern = (pattern == "**") ? "*" : pattern; _flags = flags | Constants.FNM_CASEFOLD; _result = new List<string>(); _dirOnly = _pattern.LastCharacter() == '/'; _stripTwo = false; }
public CassettePlatformAdaptationLayer(PlatformAdaptationLayer innerPal, Func<IDirectory> getDirectory) { this.innerPal = innerPal; this.getDirectory = getDirectory; }
private static IList<string>/*!*/ DoGlob(PlatformAdaptationLayer/*!*/ pal, string/*!*/ pattern, int flags) { GlobMatcher matcher = new GlobMatcher(pal, pattern, flags); return matcher.DoGlob(); }
private static object ChangeDirectory(PlatformAdaptationLayer/*!*/ pal, string/*!*/ strDir, MutableString/*!*/ dir, BlockParam block) { if (block == null) { SetCurrentDirectory(pal, strDir); return 0; } string current = pal.CurrentDirectory; try { SetCurrentDirectory(pal, strDir); object result; block.Yield(dir, out result); return result; } finally { SetCurrentDirectory(pal, current); } }
private static Stream OpenFile(PlatformAdaptationLayer pal, string name, FileMode fileMode, FileAccess fileAccess, FileShare fileShare) { if (pal.DirectoryExists(name)) { // TODO: properly set errno throw PythonOps.IOError("[Errno 13] Permission denied"); } return pal.OpenInputFileStream(name, fileMode, fileAccess, fileShare); }