diff --git a/core/includes/file.inc b/core/includes/file.inc index ed4bdce..78fc08e 100644 --- a/core/includes/file.inc +++ b/core/includes/file.inc @@ -931,8 +931,35 @@ function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXIST } // Make sure the .htaccess files are present. file_ensure_htaccess(); + + // Perform the replace operation. Since there could be multiple processes + // writing to the same file, the best option is to create a temporary file in + // the same directory and then rename it to the destination. A temporary file + // is needed if the directory is mounted on a separate machine; thus ensuring + // the rename command stays local. + $result = FALSE; + if ($replace == FILE_EXISTS_REPLACE) { + // Get a temporary filename in the destination directory. + $temporary_file = drupal_tempnam(drupal_dirname($destination), 'file'); + // Place contents in the temporary file. + if ($temporary_file && @copy($source, $temporary_file)) { + if (!$result = @rename($temporary_file, $destination)) { + // Unlink and try again for windows. Rename on windows does not replace + // the file if it already exists. + @unlink($destination); + $result = @rename($temporary_file, $destination); + } + // Remove temporary_file if rename failed. + if (!$result) { + @unlink($temporary_file); + } + } + } // Perform the copy operation. - if (!@copy($source, $destination)) { + else { + $result = @copy($source, $destination); + } + if ($result === FALSE) { // If the copy failed and realpaths exist, retry the operation using them // instead. if ($real_source === FALSE || $real_destination === FALSE || !@copy($real_source, $real_destination)) {