2222 */
2323class Filesystem
2424{
25+ private static $ lastError ;
26+
2527 /**
2628 * Copies a file.
2729 *
@@ -96,12 +98,11 @@ public function mkdir($dirs, $mode = 0777)
9698 continue ;
9799 }
98100
99- if (true !== @mkdir ($ dir , $ mode , true )) {
100- $ error = error_get_last ();
101+ if (!self ::box ('mkdir ' , $ dir , $ mode , true )) {
101102 if (!is_dir ($ dir )) {
102103 // The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one
103- if ($ error ) {
104- throw new IOException (sprintf ('Failed to create "%s": %s. ' , $ dir , $ error [ ' message ' ] ), 0 , null , $ dir );
104+ if (self :: $ lastError ) {
105+ throw new IOException (sprintf ('Failed to create "%s": %s. ' , $ dir , self :: $ lastError ), 0 , null , $ dir );
105106 }
106107 throw new IOException (sprintf ('Failed to create "%s" ' , $ dir ), 0 , null , $ dir );
107108 }
@@ -170,20 +171,17 @@ public function remove($files)
170171 foreach ($ files as $ file ) {
171172 if (is_link ($ file )) {
172173 // See https://bugs.php.net/52176
173- if (!@(unlink ($ file ) || '\\' !== DIRECTORY_SEPARATOR || rmdir ($ file )) && file_exists ($ file )) {
174- $ error = error_get_last ();
175- throw new IOException (sprintf ('Failed to remove symlink "%s": %s. ' , $ file , $ error ['message ' ]));
174+ if (!(self ::box ('unlink ' , $ file ) || '\\' !== DIRECTORY_SEPARATOR || self ::box ('rmdir ' , $ file )) && file_exists ($ file )) {
175+ throw new IOException (sprintf ('Failed to remove symlink "%s": %s. ' , $ file , self ::$ lastError ));
176176 }
177177 } elseif (is_dir ($ file )) {
178178 $ this ->remove (new \FilesystemIterator ($ file , \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS ));
179179
180- if (!@rmdir ($ file ) && file_exists ($ file )) {
181- $ error = error_get_last ();
182- throw new IOException (sprintf ('Failed to remove directory "%s": %s. ' , $ file , $ error ['message ' ]));
180+ if (!self ::box ('rmdir ' , $ file ) && file_exists ($ file )) {
181+ throw new IOException (sprintf ('Failed to remove directory "%s": %s. ' , $ file , self ::$ lastError ));
183182 }
184- } elseif (!@unlink ($ file ) && file_exists ($ file )) {
185- $ error = error_get_last ();
186- throw new IOException (sprintf ('Failed to remove file "%s": %s. ' , $ file , $ error ['message ' ]));
183+ } elseif (!self ::box ('unlink ' , $ file ) && file_exists ($ file )) {
184+ throw new IOException (sprintf ('Failed to remove file "%s": %s. ' , $ file , self ::$ lastError ));
187185 }
188186 }
189187 }
@@ -337,16 +335,14 @@ public function symlink($originDir, $targetDir, $copyOnWindows = false)
337335
338336 $ this ->mkdir (dirname ($ targetDir ));
339337
340- $ ok = false ;
341338 if (is_link ($ targetDir )) {
342- if (readlink ($ targetDir ) != $ originDir ) {
343- $ this ->remove ($ targetDir );
344- } else {
345- $ ok = true ;
339+ if (readlink ($ targetDir ) === $ originDir ) {
340+ return ;
346341 }
342+ $ this ->remove ($ targetDir );
347343 }
348344
349- if (!$ ok && true !== @ symlink ( $ originDir , $ targetDir )) {
345+ if (!self :: box ( ' symlink ' , $ originDir , $ targetDir )) {
350346 $ this ->linkException ($ originDir , $ targetDir , 'symbolic ' );
351347 }
352348 }
@@ -378,7 +374,7 @@ public function hardlink($originFile, $targetFiles)
378374 $ this ->remove ($ targetFile );
379375 }
380376
381- if (true !== @ link ( $ originFile , $ targetFile )) {
377+ if (! self :: box ( ' link ' , $ originFile , $ targetFile )) {
382378 $ this ->linkException ($ originFile , $ targetFile , 'hard ' );
383379 }
384380 }
@@ -391,9 +387,8 @@ public function hardlink($originFile, $targetFiles)
391387 */
392388 private function linkException ($ origin , $ target , $ linkType )
393389 {
394- $ report = error_get_last ();
395- if (is_array ($ report )) {
396- if ('\\' === DIRECTORY_SEPARATOR && false !== strpos ($ report ['message ' ], 'error code(1314) ' )) {
390+ if (self ::$ lastError ) {
391+ if ('\\' === DIRECTORY_SEPARATOR && false !== strpos (self ::$ lastError , 'error code(1314) ' )) {
397392 throw new IOException (sprintf ('Unable to create %s link due to error code 1314: \'A required privilege is not held by the client \'. Do you have the required Administrator-rights? ' , $ linkType ), 0 , null , $ target );
398393 }
399394 }
@@ -743,4 +738,29 @@ private function getSchemeAndHierarchy(string $filename): array
743738
744739 return 2 === count ($ components ) ? array ($ components [0 ], $ components [1 ]) : array (null , $ components [0 ]);
745740 }
741+
742+ private static function box ($ func )
743+ {
744+ self ::$ lastError = null ;
745+ \set_error_handler (__CLASS__ .'::handleError ' );
746+ try {
747+ $ result = \call_user_func_array ($ func , \array_slice (\func_get_args (), 1 ));
748+ \restore_error_handler ();
749+
750+ return $ result ;
751+ } catch (\Throwable $ e ) {
752+ } catch (\Exception $ e ) {
753+ }
754+ \restore_error_handler ();
755+
756+ throw $ e ;
757+ }
758+
759+ /**
760+ * @internal
761+ */
762+ public static function handleError ($ type , $ msg )
763+ {
764+ self ::$ lastError = $ msg ;
765+ }
746766}
0 commit comments