Merge pull request #4872 from kumpera/add_test_for_eloop
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Wed, 24 May 2017 20:25:41 +0000 (16:25 -0400)
committerGitHub <noreply@github.com>
Wed, 24 May 2017 20:25:41 +0000 (16:25 -0400)
[runtime] Fix runtime behavior when dealing with missing symlinks

mcs/class/corlib/System.IO/FileStream.cs
mcs/class/corlib/Test/System.IO/FileTest.cs
mcs/class/corlib/Test/System/DecimalTest-Microsoft.cs
mono/metadata/w32error-unix.c
mono/metadata/w32error.h
mono/metadata/w32file-unix.c

index 664d9305745369610b87f6ce3d9a44050db45507..f6b752d1784fdb631a7f8439de3426608c39c963 100644 (file)
@@ -224,14 +224,6 @@ namespace System.IO
                                }
                        }
 
-                       if (access == FileAccess.Read && mode != FileMode.Create && mode != FileMode.OpenOrCreate &&
-                                       mode != FileMode.CreateNew && !File.Exists (path)) {
-                               // don't leak the path information for isolated storage
-                               string msg = Locale.GetText ("Could not find file \"{0}\".");
-                               string fname = GetSecureFileName (path);
-                               throw new FileNotFoundException (String.Format (msg, fname), fname);
-                       }
-
                        // IsolatedStorage needs to keep the Name property to the default "[Unknown]"
                        if (!anonymous)
                                this.name = path;
index cf95e49fa3a8774831a9cefea2ab49ea12d3ff9d..4fc95243fe0b899020c9f96256de8d9387082442 100644 (file)
@@ -14,6 +14,8 @@ using System;
 using System.IO;
 using System.Globalization;
 using System.Threading;
+using System.Runtime.InteropServices;
+
 
 using NUnit.Framework;
 
@@ -2680,5 +2682,53 @@ namespace MonoTests.System.IO
                        MoveTest (FileAccess.ReadWrite, FileShare.Write | FileShare.Delete, true);
                        MoveTest (FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete, true);
                }
+
+
+               [DllImport ("libc", SetLastError=true)]
+               public static extern int symlink (string oldpath, string newpath);
+
+               [Test]
+               public void SymLinkLoop ()
+               {
+                       if (!RunningOnUnix)
+                               Assert.Ignore ("Symlink are hard on windows");
+
+                       var name1 = Path.GetRandomFileName ();
+                       var name2 = Path.GetRandomFileName ();
+
+                       var path1 = Path.Combine (Path.GetTempPath (), name1);
+                       var path2 = Path.Combine (Path.GetTempPath (), name2);
+
+                       File.Delete (path1);
+                       File.Delete (path2);
+
+                       try {
+                               symlink (path1, path2);
+                               symlink (path2, path1);
+
+                               Assert.IsTrue (File.Exists (path1), "File.Exists must return true for path1 symlink loop");
+                               Assert.IsTrue (File.Exists (path2), "File.Exists must return true for path2 symlink loop");
+
+                               try {
+                                       using (var f = File.Open (path1, FileMode.Open, FileAccess.Read)) {
+                                               Assert.Fail ("File.Open must throw for symlink loops");
+                                       }
+                               } catch (IOException ex) {
+                                       Assert.AreEqual (0x80070781u, (uint)ex.HResult, "Ensure HRESULT is correct");
+                               }
+
+                               File.Delete (path1); //Delete must not throw and must work
+                               Assert.IsFalse (File.Exists (path1), "File.Delete must delete symlink loops");
+
+                       } finally {
+                               try {
+                                       File.Delete (path1);
+                                       File.Delete (path2);
+                               } catch (IOException) {
+                                       //Don't double fault any exception from the tests.
+                               }
+
+                       }
+               }
        }
 }
index 261e9b5692537a0593711614e27b619b917e3637..c168a31e4267f0059f18815f65a7b5043ff16872 100644 (file)
@@ -14,6 +14,8 @@ using System.Runtime.CompilerServices;
 using System.Threading;
 using System.Collections.Generic;
 
+#pragma warning disable CS1718
+
 namespace MonoTests.System
 {
        [TestFixture]
index dbbc43bc6f86643cbc5ec0a5706a45490091dddc..df41473dfe896fbc0e1fbe07c82f20b00a360eeb 100644 (file)
@@ -65,7 +65,7 @@ mono_w32error_unix_to_win32 (guint32 error)
        case EIO: return ERROR_INVALID_HANDLE;
        case EINTR: return ERROR_IO_PENDING; /* best match I could find */
        case EPIPE: return ERROR_WRITE_FAULT;
-       case ELOOP: return ERROR_ACCESS_DENIED; /* Empirically found by testing desktop dotnet. */
+       case ELOOP: return ERROR_CANT_RESOLVE_FILENAME;
 
        default:
                g_error ("%s: unknown error (%d) \"%s\"", __FILE__, error, g_strerror (error));
index c8fb1717a52225a1bb1fda4186822b821fc2a1b0..439bdd81a2a0d366e5f1a3fec63ac8448cbfed49 100644 (file)
@@ -42,6 +42,7 @@
 #define ERROR_FILENAME_EXCED_RANGE 206
 #define ERROR_DIRECTORY            267
 #define ERROR_IO_PENDING           997
+#define ERROR_CANT_RESOLVE_FILENAME 1921
 #define ERROR_ENCRYPTION_FAILED    6000
 #define WSAEINTR                   10004
 #define WSAEBADF                   10009
index f6e4d2df5138873927882d9bd3cda436dcba411b..6fcb0f691f19ed0ec8c362698b4ee38fe6893e9a 100644 (file)
@@ -2518,7 +2518,6 @@ gboolean mono_w32file_delete(const gunichar2 *name)
        gchar *filename;
        gint retval;
        gboolean ret = FALSE;
-       guint32 attrs;
 #if 0
        struct stat statbuf;
        FileShare *shareinfo;
@@ -2539,14 +2538,6 @@ gboolean mono_w32file_delete(const gunichar2 *name)
                return(FALSE);
        }
 
-       attrs = mono_w32file_get_attributes (name);
-       if (attrs == INVALID_FILE_ATTRIBUTES) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: file attributes error", __func__);
-               /* Error set by mono_w32file_get_attributes() */
-               g_free (filename);
-               return(FALSE);
-       }
-
 #if 0
        /* Check to make sure sharing allows us to open the file for
         * writing.  See bug 323389.
@@ -3748,7 +3739,7 @@ mono_w32file_get_attributes (const gunichar2 *name)
        }
 
        result = _wapi_stat (utf8_name, &buf);
-       if (result == -1 && errno == ENOENT) {
+       if (result == -1 && (errno == ENOENT || errno == ELOOP)) {
                /* Might be a dangling symlink... */
                result = _wapi_lstat (utf8_name, &buf);
        }