Skip to content
This repository has been archived by the owner on Oct 23, 2019. It is now read-only.

Mono/Linux Improvements #25

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions Source/ClassLibrary/DateTime.CLR/DateTime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1544,8 +1544,16 @@ public static int MakeTime(int hour, int minute, int second, int month, int day,
default:
PhpException.ArgumentValueNotSupported("daylightSaving", daylightSaving);
break;
}
return DateTimeUtils.UtcToUnixTimeStamp(TimeZoneInfo.ConvertTimeToUtc(local, zone));
}
try
{
return DateTimeUtils.UtcToUnixTimeStamp(TimeZoneInfo.ConvertTimeToUtc(local, zone));
}
catch (Exception e)
{
// IX: Was throwing "System.ArgumentException: dateTime parameter is an invalid time" for mktime(0,0,0,10,10,2010)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it is failing for specific input argument, do not try/catch everything, just take care of the input argument (if ... then ...)

return -1;
}
}

#endregion
Expand Down
12 changes: 10 additions & 2 deletions Source/ClassLibrary/FileSystem.CLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,18 @@ public static bool Exists(string path)
if (StatInternalTryCache(path, out url))
return true;

bool res = FileStreamWrapper.HandleNewFileSystemInfo(false, path, (p) =>
new FileInfo(p).Exists || new DirectoryInfo(p).Exists);

if (!res) {
// Check if file exists inside MSA since
// file_exists() may be used for checking for .php files
// Console.WriteLine("IX: file_exists '" + path + "' = " + res);
}

// we can't just call {Directory|File}.Exists since we have to throw warnings
// also we are not calling full stat(), it is slow
return FileStreamWrapper.HandleNewFileSystemInfo(false, path, (p) =>
new FileInfo(p).Exists || new DirectoryInfo(p).Exists);
return res;
}

return false;
Expand Down
28 changes: 26 additions & 2 deletions Source/ClassLibrary/FileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1518,8 +1518,32 @@ public static bool Lock(PhpResource handle, int operation, ref int wouldblock)
var fileStream = phpStream.RawStream as FileStream;
if (fileStream == null) return false;

//
if (EnvironmentUtils.IsDotNetFramework)
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
switch ((StreamLockOptions)operation & ~StreamLockOptions.NoBlocking)
{
case StreamLockOptions.Exclusive:
// Exclusive lock
fileStream.Lock(0, Int64.MaxValue);
return true;

/*
* TODO: Implement.
case StreamLockOptions.Shared:
// Shared lock
*/

case StreamLockOptions.Unlock:
// Unlock always succeeds
fileStream.Unlock(0, Int64.MaxValue);
return true;

default:
PhpException.FunctionNotSupported();
return false;
}

} else if (EnvironmentUtils.IsDotNetFramework)
{
return Lock_dotNET(fileStream, (StreamLockOptions)operation);
}
Expand Down
31 changes: 28 additions & 3 deletions Source/ClassLibrary/Process.CLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ private static Process CreateProcessExecutingCommand(ref string command, bool by

Process process = new Process();

// IX: Hide console window when running inside CassiniDev
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

if (bypass_shell)
{
var match = CommandLineSplitter.Match(command);
Expand All @@ -283,10 +286,33 @@ private static Process CreateProcessExecutingCommand(ref string command, bool by
PhpException.InvalidArgument("command");
return null;
}

process.StartInfo.FileName = match.Groups["filename"].Value;
process.StartInfo.Arguments = match.Groups["arguments"].Value;
}
else if (Environment.OSVersion.Platform == PlatformID.Unix)
{
// TODO: Parse commands surrounded by single and double quotes (['ls' -la] and ["ls" -la]).
// command = command.Trim();
// if (command.Substring(0, 1) == "\"") ...

int i = command.IndexOf(" ");
string bin, args;
if (i >= 0)
{
// "ls -la"
bin = command.Substring(0, i);
args = command.Substring(i + 1);

process.StartInfo.Arguments = args;
}
else
{
// "ls"
bin = command;
}
process.StartInfo.FileName = bin;
}
else
{
process.StartInfo.FileName = (Environment.OSVersion.Platform != PlatformID.Win32Windows) ? "cmd.exe" : "command.com";
Expand Down Expand Up @@ -544,14 +570,13 @@ private static int CloseProcess(Process/*!*/ process)
try
{
process.WaitForExit();
return process.ExitCode; // Throws exception when process has not started.
}
catch (Exception e)
{
PhpException.Throw(PhpError.Warning, LibResources.GetString("error_waiting_for_process_exit", e.Message));
return -1;
}

return process.ExitCode;
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion Source/ClassLibrary/Shell.CLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public static string EscapeShellArg(string arg)
sb.Replace('"', ' ');
sb.Replace('%', ' ');
sb.Append('"');
sb[0] = '\'';
sb[0] = '"';
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion Source/ClassLibrary/Web.cs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ public static string RawUrlEncode(string str)
[ImplementsFunction("urldecode")]
public static string UrlDecode(string str)
{
return HttpUtility.UrlDecode(str);
return HttpUtility.UrlDecode(str, Configuration.Application.Globalization.PageEncoding);
}

/// <summary>
Expand Down
5 changes: 5 additions & 0 deletions Source/Core/Compiler/AST/DirectVariableUse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ public override Evaluation Analyze(DirectVarUse node, Analyzer analyzer, ExInfoF
|| access == AccessType.ReadRef
|| access == AccessType.ReadUnknown))
{
<<<<<<< HEAD
// False alarms
// analyzer.ErrorSink.Add(Warnings.ThisInWriteContext, analyzer.SourceUnit, node.Position);
=======
analyzer.ErrorSink.Add(Warnings.ThisInWriteContext, analyzer.SourceUnit, node.Span);
>>>>>>> upstream/master
}
}

Expand Down
19 changes: 18 additions & 1 deletion Source/Core/Configuration.CLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1145,10 +1145,27 @@ public PathsSection()
try { current_app_dir = (http_context != null) ? http_context.Server.MapPath("/bin") : "."; } // this can throw on Mono
catch (InvalidOperationException) { current_app_dir = "bin"; }

<<<<<<< HEAD
=======
libraries = new FullPath(current_app_dir);

>>>>>>> upstream/master
string dynamic_path = (http_context != null) ? current_app_dir : Path.GetTempPath();
dynamicWrappers = new FullPath(dynamic_path);

if (Environment.OSVersion.Platform == PlatformID.Unix)
{
// Mono + Apache|XSP don't set the working directory, thus new FullPath() converts "bin" to "//bin" (mono 2.10.9) or "/bin".
// It's preferable to build a path relative to the AppDomain BaseDirectory

FullPath basePath = new FullPath(AppDomain.CurrentDomain.BaseDirectory);
libraries = /*manager =*/ natives = wrappers = typeDefs = new FullPath(current_app_dir, basePath);
dynamicWrappers = new FullPath(dynamic_path, basePath);
}
else
{
libraries = /*manager =*/ natives = wrappers = typeDefs = new FullPath(current_app_dir);
dynamicWrappers = new FullPath(dynamic_path);
}
}

/// <summary>
Expand Down
47 changes: 45 additions & 2 deletions Source/Core/Execution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,51 @@ public static int ShellExec(string command, OutputHandling handling, IList array
}
}

p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c " + command;
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
// TODO: Use same code in ShellExec() and CreateProcessExecutingCommand()
string bin, args;

command = command.Trim();
string quoteChar = "\"";
if (command.Substring(0, 1) == quoteChar)
{
// Parse commands surrounded by single and double quotes (['ls' -la] and ["ls" -la]).
int end = command.IndexOf(quoteChar, 1);
bin = command.Substring(1, end - 1);
args = command.Substring(end + 1);

// TODO: Support redirections.
args = args.Replace("2>&1", "");

p.StartInfo.Arguments = args;
// System.Console.WriteLine("bin: " + bin + ", args: " + args);
}
else
{
int i = command.IndexOf(" ");
if (i >= 0)
{
// "ls -la"
bin = command.Substring(0, i);
args = command.Substring(i + 1);

p.StartInfo.Arguments = args;
}
else
{
// "ls"
bin = command;
}
}
p.StartInfo.FileName = bin;
}
else
{
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c " + command;
}

p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
Expand Down
12 changes: 8 additions & 4 deletions Source/Core/PhpStream.CLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,14 @@ public static bool ResolvePath(ref string path, out StreamWrapper wrapper, Check

// Replace all '/' with '\'.
// path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
Debug.Assert(
path.IndexOf(Path.AltDirectorySeparatorChar) == -1 ||
(Path.AltDirectorySeparatorChar == Path.DirectorySeparatorChar), // on Mono, so ignore it
string.Format("'{0}' should not contain '{1}' char.", path, Path.AltDirectorySeparatorChar));

if (Environment.OSVersion.Platform != PlatformID.Unix)
{
Debug.Assert(
path.IndexOf(Path.AltDirectorySeparatorChar) == -1 ||
(Path.AltDirectorySeparatorChar == Path.DirectorySeparatorChar), // on Mono, so ignore it
string.Format("'{0}' should not contain '{1}' char.", path, Path.AltDirectorySeparatorChar));
}

// The file wrapper expects an absolute path w/o the scheme, others expect the scheme://url.
if (scheme != "file")
Expand Down
12 changes: 11 additions & 1 deletion Source/Core/PhpStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2415,7 +2415,17 @@ protected override int RawWrite(byte[] buffer, int offset, int count)
/// <include file='Doc/Streams.xml' path='docs/method[@name="RawFlush"]/*'/>
protected override bool RawFlush()
{
if (stream.CanWrite) stream.Flush();
try
{
if (stream.CanWrite) stream.Flush();
}
catch (System.IO.IOException)
{
// Occurs when writing to an already closed process on Mono/Linux.
// See: http://www.mail-archive.com/[email protected]/msg54300.html
// TEST CASE: proc_open('/bin/ls -la', ...)
Console.WriteLine("WARNING: Trying to write to an already closed process.");
}
return true;
}

Expand Down
26 changes: 25 additions & 1 deletion Source/Core/ScriptContext.CLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,23 @@ private void InitConstants(DualDictionary<string, object> _constants)
_constants.Add("PHP_RELEASE_VERSION", PhpVersion.Release, false);
_constants.Add("PHP_VERSION_ID", PhpVersion.Major * 10000 + PhpVersion.Minor * 100 + PhpVersion.Release, false);
_constants.Add("PHP_EXTRA_VERSION", PhpVersion.Extra, false);
_constants.Add("PHP_OS", Environment.OSVersion.Platform == PlatformID.Win32NT ? "WINNT" : "WIN32", false); // TODO: GENERICS (Unix)

string php_os = "Unknown";
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32NT:
php_os = "WINNT";
break;
case PlatformID.Win32S:
case PlatformID.Win32Windows:
case PlatformID.WinCE:
php_os = "WIN32";
break;
case PlatformID.Unix:
php_os = "Linux";
break;
}
_constants.Add("PHP_OS", php_os, false);
_constants.Add("PHP_SAPI", (System.Web.HttpContext.Current == null) ? "cli" : "isapi", false);
_constants.Add("DIRECTORY_SEPARATOR", FullPath.DirectorySeparatorString, false);
_constants.Add("PATH_SEPARATOR", Path.PathSeparator.ToString(), false);
Expand Down Expand Up @@ -560,6 +576,14 @@ public object DynamicInclude(
DTypeDesc includer,
InclusionTypes inclusionType)
{
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
// Fix for absolute-path-includes on Unix filesystems.
// Example: include_once('/path/app\libs\include.php')
// HACK: Translate "\" to "/"
includerFileRelPath = includerFileRelPath.Replace('\\', '/');
}

ApplicationConfiguration app_config = Configuration.Application;

// determines inclusion behavior:
Expand Down
18 changes: 18 additions & 0 deletions Source/Core/StreamWrappers.CLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,15 @@ private static long ToStatUnixTimeStamp(FileSystemInfo info, Func<FileSystemInfo
/// </summary>
public static FileModeFlags GetFileMode(FileInfo info)
{
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
// Only some flags are currently supported
// TODO: Use info.GetAccessControl()?
FileModeFlags flags = new FileModeFlags();
if (!info.IsReadOnly) flags |= FileModeFlags.Write;
return flags;
}

System.Security.AccessControl.AuthorizationRuleCollection acl;

try
Expand All @@ -281,6 +290,15 @@ public static FileModeFlags GetFileMode(FileInfo info)
/// </summary>
public static FileModeFlags GetFileMode(DirectoryInfo info)
{
if (Environment.OSVersion.Platform == PlatformID.Unix)
{
// Only some flags are currently supported
// TODO: Use info.GetAccessControl()?
FileModeFlags flags = new FileModeFlags();
if ((info.Attributes & FileAttributes.ReadOnly) == 0) flags |= FileModeFlags.Write;
return flags;
}

System.Security.AccessControl.AuthorizationRuleCollection acl;

try
Expand Down
Loading