103    public static function recursiveCopy(
string $origin, 
string $destination) : void{
 
  104        if(!is_dir($origin)){
 
  105            throw new \RuntimeException(
"$origin does not exist, or is not a directory");
 
  107        if(!is_dir($destination)){
 
  108            if(file_exists($destination)){
 
  109                throw new \RuntimeException(
"$destination already exists, and is not a directory");
 
  111            if(!is_dir(dirname($destination))){
 
  113                throw new \RuntimeException(
"The parent directory of $destination does not exist, or is not a directory");
 
  116                ErrorToExceptionHandler::trap(fn() => mkdir($destination));
 
  117            }
catch(\ErrorException $e){
 
  118                if(!is_dir($destination)){
 
  119                    throw new \RuntimeException(
"Failed to create output directory $destination: " . $e->getMessage());
 
  123        self::recursiveCopyInternal($origin, $destination);
 
 
  139                self::recursiveCopyInternal(Path::join($origin, $object), Path::join($destination, $object));
 
  171                $result = ltrim(str_replace($cleanPath, $replacement, $result), 
"/");
 
  188        }
catch(\ErrorException $e){
 
  189            throw new \InvalidArgumentException(
"Failed to open lock file: " . $e->getMessage(), 0, $e);
 
  191        if(!flock($resource, LOCK_EX | LOCK_NB)){
 
  194            flock($resource, LOCK_SH);
 
  195            $pid = Utils::assumeNotFalse(stream_get_contents($resource), 
"This is a known valid file resource, at worst we should receive an empty string");
 
  196            if(preg_match(
'/^\d+$/', $pid) === 1){
 
  201        ftruncate($resource, 0);
 
  202        fwrite($resource, (
string) getmypid());
 
  204        flock($resource, LOCK_SH); 
 
  205        self::$lockFileHandles[realpath($lockFilePath)] = $resource; 
 
 
  215        $lockFilePath = realpath($lockFilePath);
 
  216        if($lockFilePath === 
false){
 
  217            throw new \InvalidArgumentException(
"Invalid lock file path");
 
  219        if(isset(self::$lockFileHandles[$lockFilePath])){
 
  220            flock(self::$lockFileHandles[$lockFilePath], LOCK_UN);
 
  221            fclose(self::$lockFileHandles[$lockFilePath]);
 
  222            unset(self::$lockFileHandles[$lockFilePath]);
 
  223            @unlink($lockFilePath);
 
 
  238    public static function safeFilePutContents(
string $fileName, 
string $contents, 
int $flags = 0, $context = 
null) : void{
 
  239        $directory = dirname($fileName);
 
  240        if(!is_dir($directory)){
 
  241            throw new \RuntimeException(
"Target directory path does not exist or is not a directory");
 
  243        if(is_dir($fileName)){
 
  244            throw new \RuntimeException(
"Target file path already exists and is not a file");
 
  250            $temporaryFileName = $fileName . 
".$counter.tmp";
 
  252        }
while(is_dir($temporaryFileName));
 
  255            ErrorToExceptionHandler::trap(fn() => $context !== 
null ?
 
  256                file_put_contents($temporaryFileName, $contents, $flags, $context) :
 
  257                file_put_contents($temporaryFileName, $contents, $flags)
 
  259        }
catch(\ErrorException $filePutContentsException){
 
  261                @unlink($temporaryFileName, $context) :
 
  262                @unlink($temporaryFileName);
 
  263            throw new \RuntimeException(
"Failed to write to temporary file $temporaryFileName: " . $filePutContentsException->getMessage(), 0, $filePutContentsException);
 
  266        $renameTemporaryFileResult = $context !== 
null ?
 
  267            @rename($temporaryFileName, $fileName, $context) :
 
  268            @rename($temporaryFileName, $fileName);
 
  269        if(!$renameTemporaryFileResult){
 
  285                ErrorToExceptionHandler::trap(fn() => $context !== 
null ?
 
  286                    copy($temporaryFileName, $fileName, $context) :
 
  287                    copy($temporaryFileName, $fileName)
 
  289            }
catch(\ErrorException $copyException){
 
  290                throw new \RuntimeException(
"Failed to move temporary file contents into target file: " . $copyException->getMessage(), 0, $copyException);
 
  292            @unlink($temporaryFileName);