Index: wp-admin/includes/update.php
===================================================================
--- wp-admin/includes/update.php	(revision 25297)
+++ wp-admin/includes/update.php	(working copy)
@@ -57,6 +57,36 @@
 	return $result;
 }
 
+function get_core_checksums( $version ) {
+	if ( $checksums = get_site_transient( "core_checksums_$version" ) )
+		return $checksums;
+
+	$url = 'http://api.wordpress.org/core/checksum/1.0/?' . http_build_query( array( 'version' => $version ), null, '&' );
+
+	if ( wp_http_supports( array( 'ssl' ) ) )
+		$url = set_url_scheme( $url, 'https' );
+
+	$options = array(
+		'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3 ),
+		'user-agent' => 'WordPress/' . $version . '; ' . home_url( '/' )
+	);
+
+	$response = wp_remote_get( $url, $options );
+
+	if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) )
+		return false;
+
+	$body = trim( wp_remote_retrieve_body( $response ) );
+	$body = json_decode( $body, true );
+
+	if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) )
+		return false;
+
+	set_site_transient( "core_checksums_$version", $body['checksums'], HOUR_IN_SECONDS );
+
+	return $body['checksums'];
+}
+
 function dismiss_core_update( $update ) {
 	$dismissed = get_site_option( 'dismissed_update_core' );
 	$dismissed[ $update->current . '|' . $update->locale ] = true;
Index: wp-admin/includes/class-wp-upgrader.php
===================================================================
--- wp-admin/includes/class-wp-upgrader.php	(revision 25297)
+++ wp-admin/includes/class-wp-upgrader.php	(working copy)
@@ -1090,11 +1090,15 @@
 
 		$wp_dir = trailingslashit($wp_filesystem->abspath());
 
+		$no_partial = false;
+		if ( ! $this->check_files() )
+			$no_partial = true;
+
 		// If partial update is returned from the API, use that, unless we're doing a reinstall.
 		// If we cross the new_bundled version number, then use the new_bundled zip.
 		// Don't though if the constant is set to skip bundled items.
 		// If the API returns a no_content zip, go with it. Finally, default to the full zip.
-		if ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version )
+		if ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version && ! $no_partial )
 			$to_download = 'partial';
 		elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' )
 			&& ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) )
@@ -1129,6 +1133,26 @@
 		return $result;
 	}
 
+	function check_files() {
+		global $wp_version;
+
+		if ( ! function_exists( 'md5_file' ) )
+			return false;
+
+		$checksums = get_core_checksums( $wp_version );
+
+		if ( empty( $checksums ) )
+			return false;
+
+		$home = get_home_path();
+
+		foreach ( $checksums as $file => $checksum ) {
+			if ( md5_file( $home . $file ) !== $checksum )
+				return false;
+		}
+
+		return true;
+	}
 }
 
 /**
Index: wp-admin/includes/update-core.php
===================================================================
--- wp-admin/includes/update-core.php	(revision 25297)
+++ wp-admin/includes/update-core.php	(working copy)
@@ -690,6 +690,19 @@
 
 	apply_filters('update_feedback', __('Installing the latest version&#8230;'));
 
+	// Check to see which files don't really need updating
+	$skip = array( 'wp-content' );
+	$checksums = array();
+	if ( function_exists( 'md5_file' ) ) {
+		$checksums = get_core_checksums( $wp_version );
+		if ( ! empty( $checksums ) ) {
+			foreach( $checksums as $file => $checksum ) {
+				if ( md5_file( $to . $file ) === $checksum )
+					$skip[] = $file;
+			}
+		}
+	}
+
 	// Create maintenance file to signal that we are upgrading
 	$maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
 	$maintenance_file = $to . '.maintenance';
@@ -697,7 +710,37 @@
 	$wp_filesystem->put_contents($maintenance_file, $maintenance_string, FS_CHMOD_FILE);
 
 	// Copy new versions of WP files into place.
-	$result = _copy_dir($from . $distro, $to, array('wp-content') );
+	$result = _copy_dir($from . $distro, $to, $skip );
+
+	// Check to make sure everything copied correctly
+	$skip = array( 'wp-content' );
+	$failed = array();
+	if ( function_exists( 'md5_file' ) ) {
+		if ( ! empty( $checksums ) ) {
+			foreach( $checksums as $file => $checksum ) {
+				if ( md5_file( $to . $file ) === $checksum )
+					$skip[] = $file;
+				else
+					$failed[] = $file;
+			}
+		}
+	}
+
+	// Some files didn't copy properly
+	if ( ! empty( $failed ) ) {
+		$total_size = 0;
+		foreach ( $failed as $file => $checksum )
+			$total_size += filesize( $from . $file );
+
+		if ( $total_size >= disk_free_space( $to ) ) {
+			// If we don't have enough free space, it isn't worth trying again
+			$result = new WP_Error( 'disk_full', __( "There isn't enough free disk space to complete the upgrade." ), $to );
+		} else {
+			// Let's wait a few seconds, in case it's some sort of temporary destination issue, then try once more
+			sleep( 3 );
+			$result = _copy_dir( $from . $distro, $to, $skip );
+		}
+	}
 
 	// Custom Content Directory needs updating now.
 	// Copy Languages
