diff --git modules/simpletest/simpletest.info modules/simpletest/simpletest.info
index 07877e9..43414d6 100644
--- modules/simpletest/simpletest.info
+++ modules/simpletest/simpletest.info
@@ -42,3 +42,4 @@ files[] = tests/upgrade/upgrade.test
 files[] = tests/upgrade/upgrade.comment.test
 files[] = tests/upgrade/upgrade.node.test
 files[] = tests/upgrade/upgrade.taxonomy.test
+files[] = tests/upgrade/upgrade.upload.test
diff --git modules/simpletest/tests/upgrade/drupal-6.upload.database.php modules/simpletest/tests/upgrade/drupal-6.upload.database.php
new file mode 100644
index 0000000..048aee0
--- /dev/null
+++ modules/simpletest/tests/upgrade/drupal-6.upload.database.php
@@ -0,0 +1,358 @@
+<?php
+// $Id$
+
+db_insert('files')->fields(array(
+  'fid',
+  'uid',
+  'filename',
+  'filepath',
+  'filemime',
+  'filesize',
+  'status',
+  'timestamp',
+))
+->values(array(
+  'fid' => '1',
+  'uid' => '1',
+  'filename' => 'powered-blue-80x15.png',
+  'filepath' => 'sites/default/files/powered-blue-80x15.png',
+  'filemime' => 'image/png',
+  'filesize' => '1011',
+  'status' => '1',
+  'timestamp' => '1285700240',
+))
+->values(array(
+  'fid' => '2',
+  'uid' => '1',
+  'filename' => 'powered-blue-80x15.png',
+  'filepath' => 'sites/default/files/powered-blue-80x15_0.png',
+  'filemime' => 'image/png',
+  'filesize' => '1011',
+  'status' => '1',
+  'timestamp' => '1285700317',
+))
+->values(array(
+  'fid' => '3',
+  'uid' => '1',
+  'filename' => 'powered-blue-88x31.png',
+  'filepath' => 'sites/default/files/powered-blue-88x31.png',
+  'filemime' => 'image/png',
+  'filesize' => '2113',
+  'status' => '1',
+  'timestamp' => '1285700343',
+))
+->values(array(
+  'fid' => '4',
+  'uid' => '1',
+  'filename' => 'powered-blue-135x42.png',
+  'filepath' => 'sites/default/files/powered-blue-135x42.png',
+  'filemime' => 'image/png',
+  'filesize' => '3027',
+  'status' => '1',
+  'timestamp' => '1285700366',
+))
+->values(array(
+  'fid' => '5',
+  'uid' => '1',
+  'filename' => 'powered-black-80x15.png',
+  'filepath' => 'sites/default/files/powered-black-80x15.png',
+  'filemime' => 'image/png',
+  'filesize' => '1467',
+  'status' => '1',
+  'timestamp' => '1285700529',
+))
+->values(array(
+  'fid' => '6',
+  'uid' => '1',
+  'filename' => 'powered-black-135x42.png',
+  'filepath' => 'sites/default/files/powered-black-135x42.png',
+  'filemime' => 'image/png',
+  'filesize' => '2817',
+  'status' => '1',
+  'timestamp' => '1285700552',
+))
+->values(array(
+  'fid' => '7',
+  'uid' => '1',
+  'filename' => 'forum-hot-new.png',
+  'filepath' => 'sites/default/files/forum-hot-new.png',
+  'filemime' => 'image/png',
+  'filesize' => '237',
+  'status' => '1',
+  'timestamp' => '1285708937',
+))
+->values(array(
+  'fid' => '8',
+  'uid' => '1',
+  'filename' => 'forum-hot.png',
+  'filepath' => 'sites/default/files/forum-hot.png',
+  'filemime' => 'image/png',
+  'filesize' => '229',
+  'status' => '1',
+  'timestamp' => '1285708944',
+))
+->values(array(
+  'fid' => '9',
+  'uid' => '1',
+  'filename' => 'forum-new.png',
+  'filepath' => 'sites/default/files/forum-new.png',
+  'filemime' => 'image/png',
+  'filesize' => '175',
+  'status' => '1',
+  'timestamp' => '1285708950',
+))
+->values(array(
+  'fid' => '10',
+  'uid' => '1',
+  'filename' => 'forum-sticky.png',
+  'filepath' => 'sites/default/files/forum-sticky.png',
+  'filemime' => 'image/png',
+  'filesize' => '329',
+  'status' => '1',
+  'timestamp' => '1285708957',
+))
+->execute();
+
+db_insert('node')->fields(array(
+  'nid',
+  'vid',
+  'type',
+  'language',
+  'title',
+  'uid',
+  'status',
+  'created',
+  'changed',
+  'comment',
+  'promote',
+  'moderate',
+  'sticky',
+  'tnid',
+  'translate',
+))
+->values(array(
+  'nid' => '38',
+  'vid' => '51',
+  'type' => 'page',
+  'language' => '',
+  'title' => 'node title 38 revision 51',
+  'uid' => '1',
+  'status' => '1',
+  'created' => '1285700317',
+  'changed' => '1285700600',
+  'comment' => '0',
+  'promote' => '0',
+  'moderate' => '0',
+  'sticky' => '0',
+  'tnid' => '0',
+  'translate' => '0',
+))
+->values(array(
+  'nid' => '39',
+  'vid' => '52',
+  'type' => 'page',
+  'language' => '',
+  'title' => 'node title 39 revision 53',
+  'uid' => '1',
+  'status' => '1',
+  'created' => '1285709012',
+  'changed' => '1285709012',
+  'comment' => '0',
+  'promote' => '0',
+  'moderate' => '0',
+  'sticky' => '0',
+  'tnid' => '0',
+  'translate' => '0',
+))
+ ->execute();
+
+db_insert('node_revisions')->fields(array(
+  'nid',
+  'vid',
+  'uid',
+  'title',
+  'body',
+  'teaser',
+  'log',
+  'timestamp',
+  'format',
+))
+->values(array(
+  'nid' => '38',
+  'vid' => '50',
+  'uid' => '1',
+  'title' => 'node title 38 revision 50',
+  'body' => "Attachments:\r\npowered-blue-80x15.png\r\npowered-blue-88x31.png\r\npowered-blue-135x42.png",
+  'teaser' => "Attachments:\r\npowered-blue-80x15.png\r\npowered-blue-88x31.png\r\npowered-blue-135x42.png",
+  'log' => '',
+  'timestamp' => '1285700487',
+  'format' => '1',
+))
+->values(array(
+  'nid' => '38',
+  'vid' => '51',
+  'uid' => '1',
+  'title' => 'node title 38 revision 51',
+  'body' => "Attachments:\r\npowered-blue-88x31.png\r\npowered-black-80x15.png\r\npowered-black-135x42.png",
+  'teaser' => "Attachments:\r\npowered-blue-88x31.png\r\npowered-black-80x15.png\r\npowered-black-135x42.png",
+  'log' => '',
+  'timestamp' => '1285700600',
+  'format' => '1',
+))
+->values(array(
+  'nid' => '39',
+  'vid' => '52',
+  'uid' => '1',
+  'title' => 'node title 39 revision 53',
+  'body' => "Attachments:\r\nforum-hot-new.png\r\nforum-hot.png\r\nforum-sticky.png\r\nforum-new.png",
+  'teaser' => "Attachments:\r\nforum-hot-new.png\r\nforum-hot.png\r\nforum-sticky.png\r\nforum-new.png",
+  'log' => '',
+  'timestamp' => '1285709012',
+  'format' => '1',
+))
+ ->execute();
+
+db_create_table('upload', array(
+  'fields' => array(
+    'fid' => array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'default' => 0,
+    ),
+    'nid' => array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'default' => 0,
+    ),
+    'vid' => array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'default' => 0,
+    ),
+    'description' => array(
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => TRUE,
+      'default' => '',
+    ),
+    'list' => array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'default' => 0,
+      'size' => 'tiny',
+    ),
+    'weight' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'default' => 0,
+      'size' => 'tiny',
+    ),
+  ),
+  'primary key' => array(
+    'vid',
+    'fid',
+  ),
+  'indexes' => array(
+    'fid' => array(
+      'fid',
+    ),
+    'nid' => array(
+      'nid',
+    ),
+  ),
+  'module' => 'upload',
+  'name' => 'upload',
+));
+db_insert('upload')->fields(array(
+  'fid',
+  'nid',
+  'vid',
+  'description',
+  'list',
+  'weight',
+))
+->values(array(
+  'fid' => '2',
+  'nid' => '38',
+  'vid' => '50',
+  'description' => 'powered-blue-80x15.png',
+  'list' => '1',
+  'weight' => '0',
+))
+->values(array(
+  'fid' => '3',
+  'nid' => '38',
+  'vid' => '50',
+  'description' => 'powered-blue-88x31.png',
+  'list' => '1',
+  'weight' => '0',
+))
+->values(array(
+  'fid' => '4',
+  'nid' => '38',
+  'vid' => '50',
+  'description' => 'powered-blue-135x42.png',
+  'list' => '1',
+  'weight' => '0',
+))
+->values(array(
+  'fid' => '3',
+  'nid' => '38',
+  'vid' => '51',
+  'description' => 'powered-blue-88x31.png',
+  'list' => '1',
+  'weight' => '0',
+))
+->values(array(
+  'fid' => '5',
+  'nid' => '38',
+  'vid' => '51',
+  'description' => 'powered-black-80x15.png',
+  'list' => '1',
+  'weight' => '0',
+))
+->values(array(
+  'fid' => '6',
+  'nid' => '38',
+  'vid' => '51',
+  'description' => 'powered-black-135x42.png',
+  'list' => '1',
+  'weight' => '0',
+))
+->values(array(
+  'fid' => '7',
+  'nid' => '39',
+  'vid' => '52',
+  'description' => 'forum-hot-new.png',
+  'list' => '1',
+  'weight' => '-4',
+))
+->values(array(
+  'fid' => '8',
+  'nid' => '39',
+  'vid' => '52',
+  'description' => 'forum-hot.png',
+  'list' => '1',
+  'weight' => '-3',
+))
+->values(array(
+  'fid' => '10',
+  'nid' => '39',
+  'vid' => '52',
+  'description' => 'forum-sticky.png',
+  'list' => '1',
+  'weight' => '-2',
+))
+->values(array(
+  'fid' => '9',
+  'nid' => '39',
+  'vid' => '52',
+  'description' => 'forum-new.png',
+  'list' => '1',
+  'weight' => '-1',
+))
+->execute();
diff --git modules/simpletest/tests/upgrade/upgrade.upload.test modules/simpletest/tests/upgrade/upgrade.upload.test
new file mode 100644
index 0000000..eb32e9a
--- /dev/null
+++ modules/simpletest/tests/upgrade/upgrade.upload.test
@@ -0,0 +1,66 @@
+<?php
+// $Id: upgrade.comment.test,v 1.1 2010/09/11 21:52:59 webchick Exp $
+
+/**
+ * Upgrade test for comment.module.
+ */
+class UploadUpgradePathTestCase extends UpgradePathTestCase {
+  public static function getInfo() {
+    return array(
+      'name'  => 'Upload upgrade path',
+      'description'  => 'Upload upgrade path tests.',
+      'group' => 'Upgrade path',
+    );
+  }
+
+  public function setUp() {
+    // Path to the database dump files.
+    $this->databaseDumpFiles = array(
+      drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.filled.database.php',
+      drupal_get_path('module', 'simpletest') . '/tests/upgrade/drupal-6.upload.database.php',
+    );
+    parent::setUp();
+
+    $this->uninstallModulesExcept(array('upload'));
+  }
+
+  /**
+   * Test a successful upgrade.
+   */
+  public function testUploadUpgrade() {
+    $this->assertTrue($this->performUpgrade(), t('The upgrade was completed successfully.'));
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', 'node');
+    $query->entityCondition('bundle', 'page');
+    $query->age(FIELD_LOAD_REVISION);
+    $query->fieldCondition('upload');
+    $entities = $query->execute();
+    $revisions = $entities['node'];
+    // Node revisions 50-52 should have uploaded files.
+    $this->assertTrue((isset($revisions[50]) && isset($revisions[51]) && isset($revisions[52])), 'Nodes with uploaded files now contain filefield data.');
+    // The test database lists uploaded filenames in the body of each node with
+    // uploaded files attached. Make sure all files are there in the same order.
+    foreach ($revisions as $vid => $revision) {
+      $node = node_load($revision->nid, $vid);
+
+      // Assemble a list of the filenames as recorded in the node body before
+      // the upgrade.
+      $recorded_filenames = preg_split('/\s+/', $node->body[LANGUAGE_NONE][0]['value']);
+      // The first line of the node body should be "Attachments:"
+      if (strstr($recorded_filenames[0], "Attachments:")) {
+        unset($recorded_filenames[0]);
+      }
+      $recorded_filenames = array_values($recorded_filenames);
+
+      $files = $node->upload[LANGUAGE_NONE];
+      // Assemble a list of the filenames as they exist after the upgrade.
+      $filenames = array();
+      foreach ($files as $file) {
+        $filenames[] = $file['filename'];
+      }
+
+      $diff = array_diff($filenames, $recorded_filenames);
+      $this->assertTrue(empty($diff), 'The uploaded files are present in the same order after the upgrade.');
+    }
+  }
+}
diff --git modules/system/system.install modules/system/system.install
index e00883e..3b24f1b 100644
--- modules/system/system.install
+++ modules/system/system.install
@@ -2586,132 +2586,169 @@ function system_update_7059() {
 }
 
 /**
- * Migrate upload.module to file.module.
+ * Create fields in preparation for migrating upload.module to file.module.
  */
-function system_update_7060(&$sandbox) {
+function system_update_7060() {
   if (!db_table_exists('upload')) {
     return;
   }
 
-  if (!isset($sandbox['progress'])) {
-    // Initialize batch update information.
-    $sandbox['progress'] = 0;
-    $sandbox['last_vid_processed'] = -1;
-    $sandbox['max'] = db_query("SELECT COUNT(DISTINCT u.vid) FROM {upload} u")->fetchField();
-
-    // Check which node types have upload.module attachments enabled.
-    $context['types'] = array();
-    foreach (node_type_get_types() as $node_type => $node_info) {
-      if (variable_get('upload_' . $node_type, 1)) {
-        $context['types'][$node_type] = $node_type;
-      }
-      variable_del('upload_' . $node_type);
+  // Check which node types have upload.module attachments enabled.
+  $context['types'] = array();
+  foreach (_update_7000_node_get_types() as $node_type) {
+    if (variable_get('upload_' . $node_type->type, 0)) {
+      $context['types'][$node_type->type] = $node_type->type;
     }
+  }
 
-    // The {upload} table will be deleted when this update is complete so we
-    // want to be careful to migrate all the data, even for node types that
-    // may have had attachments disabled after files were uploaded. Look for
-    // any other node types referenced by the upload records and add those to
-    // the list. The admin can always remove the field later.
-    $results = db_query('SELECT DISTINCT type FROM {node} n INNER JOIN {upload} u ON n.vid = u.vid');
-    foreach ($results as $row) {
-      if (!isset($context['types'][$row->type])) {
-        drupal_set_message(t('The content type %rowtype had uploads disabled but contained uploaded file data. Uploads have been re-enabled to migrate the existing data. You may delete the "File attachments" field in the %rowtype type if this data is not necessary.', array('%rowtype' => $row->type)));
-        $context['types'][$row->type] = $row->type;
-      }
+  // The {upload} table will be deleted when this update is complete so we
+  // want to be careful to migrate all the data, even for node types that
+  // may have had attachments disabled after files were uploaded. Look for
+  // any other node types referenced by the upload records and add those to
+  // the list. The admin can always remove the field later.
+  $results = db_query('SELECT DISTINCT type FROM {node} n INNER JOIN {node_revision} nr ON n.nid = nr.nid INNER JOIN {upload} u ON nr.vid = u.vid');
+  foreach ($results as $row) {
+    if (!isset($context['types'][$row->type])) {
+      drupal_set_message(t('The content type %rowtype had uploads disabled but contained uploaded file data. Uploads have been re-enabled to migrate the existing data. You may delete the "File attachments" field in the %rowtype type if this data is not necessary.', array('%rowtype' => $row->type)));
+      $context['types'][$row->type] = $row->type;
     }
+  }
+
+  // Create a single "upload" field on all the content types that have uploads
+  // enabled, then add an instance to each enabled type.
+  if (count($context['types']) > 0) {
+    module_enable(array('file'));
+    $field = array(
+      'field_name' => 'upload',
+      'type' => 'file',
+      'module' => 'file',
+      'locked' => FALSE,
+      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+      'translatable' => FALSE,
+      'settings' => array(
+        'display_field' => 1,
+        'display_default' => variable_get('upload_list_default', 1),
+        'uri_scheme' => file_default_scheme(),
+        'default_file' => 0,
+      ),
+    );
 
-    // Create a single "field_upload" field on all the content types that have
-    // uploads enabled, then add an instance to each enabled type.
-    if (count($context['types']) > 0) {
-      module_enable(array('file'));
-      module_load_include('inc', 'field', 'field.crud');
-
-      $field = array(
-        'field_name' => 'file',
-        'type' => 'file',
-        'locked' => FALSE,
-        'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-        'translatable' => FALSE,
+    $upload_size = variable_get('upload_uploadsize_default', 1);
+    $instance = array(
+      'field_name' => 'upload',
+      'entity_type' => 'node',
+      'bundle' => NULL,
+      'label' => 'File attachments',
+      'required' => 0,
+      'description' => '',
+      'widget' => array(
+        'weight' => '1',
         'settings' => array(
-          'display_field' => 1,
-          'display_default' => variable_get('upload_list_default', 1),
-          'uri_scheme' => file_default_scheme(),
-          'default_file' => 0,
+          'progress_indicator' => 'throbber',
         ),
-      );
-
-      $upload_size = variable_get('upload_uploadsize_default', 1);
-      $instance = array(
-        'field_name' => 'file',
-        'entity_type' => 'node',
-        'bundle' => NULL,
-        'label' => 'File attachments',
-        'widget_type' => 'file_generic',
-        'required' => 0,
-        'description' => '',
-        'widget' => array(
-          'weight' => '1',
-          'settings' => array(
-            'progress_indicator' => 'throbber',
-          ),
-          'type' => 'file_generic',
+        'type' => 'file_generic',
+      ),
+      'settings' => array(
+        'max_filesize' => $upload_size ? ($upload_size . ' MB') : '',
+        'file_extensions' => variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'),
+        'file_directory' => '',
+        'description_field' => 1,
+      ),
+      'display' => array(
+        'default' => array(
+          'label' => 'hidden',
+          'type' => 'file_table',
+          'settings' => array(),
+          'weight' => 0,
+          'module' => 'file',
         ),
-        'settings' => array(
-          'max_filesize' => $upload_size ? ($upload_size . ' MB') : '',
-          'file_extensions' => variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'),
-          'file_directory' => '',
-          'description_field' => 1,
+        'full' => array(
+          'label' => 'hidden',
+          'type' => 'file_table',
+          'settings' => array(),
+          'weight' => 0,
+          'module' => 'file',
         ),
-        'display' => array(
-          'full' => array(
-            'label' => 'hidden',
-            'type' => 'file_table',
-            'settings' => array(),
-            'weight' => 0,
-            'module' => 'file',
-          ),
-          'teaser' => array(
-            'label' => 'hidden',
-            'type' => 'hidden',
-            'settings' => array(),
-            'weight' => 0,
-            'module' => NULL,
-          ),
-          'rss' => array(
-            'label' => 'hidden',
-            'type' => 'file_table',
-            'settings' => array(),
-            'weight' => 0,
-            'module' => 'file',
-          ),
+        'teaser' => array(
+          'label' => 'hidden',
+          'type' => 'hidden',
+          'settings' => array(),
+          'weight' => 0,
+          'module' => NULL,
         ),
-      );
+        'rss' => array(
+          'label' => 'hidden',
+          'type' => 'file_table',
+          'settings' => array(),
+          'weight' => 0,
+          'module' => 'file',
+        ),
+      ),
+    );
 
-      // Create the field. Save the field id for the data insertion later on.
-      $field = field_create_field($field);
-      $sandbox['field_id'] = $field['id'];
+    // Create the field.
+    _update_7000_field_create_field($field);
 
-      // Create the instances.
-      foreach ($context['types'] as $bundle) {
-        $instance['bundle'] = $bundle;
-        field_create_instance($instance);
-      }
-    }
-    else {
-      // No uploads or content types with uploads enabled.
-      db_drop_table('upload');
-      // We're done: return without specifying a #progress.
-      return;
+    // Create the instances.
+    foreach ($context['types'] as $bundle) {
+      $instance['bundle'] = $bundle;
+      _update_7000_field_create_instance($field, $instance);
+      // Now that the instance is created, we can safely delete any legacy
+      // node type information.
+      variable_del('upload_' . $bundle);
     }
   }
+  else {
+    // No uploads or content types with uploads enabled.
+    db_drop_table('upload');
+  }
+}
 
-  // Migrate a batch of files from the upload table to the appropriate field.
-  $limit = 500;
-  $result = db_query_range('SELECT DISTINCT u.fid, u.vid, u.list, u.description, n.nid, n.type FROM {upload} u INNER JOIN {node_revision} nr ON u.vid = nr.vid INNER JOIN {node} n ON n.nid = nr.nid WHERE u.vid > :lastvid ORDER BY u.vid, u.weight', 0, $limit, array(':lastvid' => $sandbox['last_vid_processed']));
+/**
+ * Migrate upload.module data to the newly created file field.
+ */
+function system_update_7061(&$sandbox) {
+  if (!db_table_exists('upload')) {
+    return;
+  }
+
+  if (!isset($sandbox['progress'])) {
+    // Retrieve a list of node revisions that have uploaded files attached.
+    // DISTINCT queries are expensive, especially when paged, so we store the
+    // data in its own table for the duration of the update.
+    $table = array(
+      'description' => t('Stores temporary data for system_update_7061.'),
+      'fields' => array('vid' => array('type' => 'int')),
+      'primary key' => array('vid'),
+    );
+    db_create_table('system_update_7061', $table);
+    $query = db_select('upload', 'u');
+    $query->distinct();
+    $query->addField('u','vid');
+    db_insert('system_update_7061')
+      ->from($query)
+      ->execute();
+
+    // Initialize batch update information.
+    $sandbox['progress'] = 0;
+    $sandbox['last_vid_processed'] = -1;
+    $sandbox['max'] = db_query("SELECT COUNT(*) FROM {system_update_7061}")->fetchField();
+  }
+
+  $node_revisions = array();
+
+  // Determine vids for this batch.
+  // Process all files attached to a given revision during the same batch.
+  $limit = 100;
+  $vids = db_query_range('SELECT vid FROM {system_update_7061} WHERE vid > :lastvid ORDER BY vid', 0, $limit, array(':lastvid' => $sandbox['last_vid_processed']))
+    ->fetchCol();
+
+  // Retrieve information on all the files attached to these revisions.
+  $result = db_query('SELECT u.fid, u.vid, u.list, u.description, n.nid, n.type, u.weight FROM {upload} u INNER JOIN {node_revision} nr ON u.vid = nr.vid INNER JOIN {node} n ON n.nid = nr.nid WHERE u.vid IN (:vids) ORDER BY u.vid, u.weight, u.fid', array(':vids' => $vids));
   foreach ($result as $record) {
-    // Note that we still reference the old files table here, since upload will
-    // not know about the new FID in the new file_managed table.
+    // For each uploaded file, retrieve the corresponding data from the old
+    // files table (since upload doesn't know about the new entry in the
+    // file_managed table).
     $file = db_select('files', 'f')
       ->fields('f', array('fid', 'uid', 'filename', 'filepath', 'filemime', 'filesize', 'status', 'timestamp'))
       ->condition('f.fid', $record->fid)
@@ -2721,35 +2758,30 @@ function system_update_7060(&$sandbox) {
       continue;
     }
 
+    // Add in the file information from the upload table.
     $file['description'] = $record->description;
     $file['display'] = $record->list;
 
+    // Create one record for each revision that contains all the uploaded files.
     $node_revisions[$record->vid]['nid'] = $record->nid;
     $node_revisions[$record->vid]['vid'] = $record->vid;
     $node_revisions[$record->vid]['type'] = $record->type;
     $node_revisions[$record->vid]['file'][LANGUAGE_NONE][] = $file;
   }
 
-  // To make sure we process an entire node all at once, toss the last node
-  // revision (which might be partial) unless it's the last one.
-  if ((count($node_revisions) > 1) && ($result->rowCount() == $limit)) {
-    array_pop($node_revisions);
-  }
-  else {
-    $finished = TRUE;
-  }
-
+  // Now that we know which files belong to which revisions, update the files'
+  // database entries, and save a reference to each file in the upload field on
+  // their node revisions.
   $basename = variable_get('file_directory_path', conf_path() . '/files');
   $scheme = file_default_scheme() . '://';
   foreach ($node_revisions as $vid => $revision) {
-    // We will convert filepaths to uri using the default scheme
-    // and stripping off the existing file directory path.
-    $fids = array();
     foreach ($revision['file'][LANGUAGE_NONE] as $delta => $file) {
-      // Insert into the file_managed table.
+      // We will convert filepaths to uri using the default scheme
+      // and stripping off the existing file directory path.
       $file['uri'] = $scheme . str_replace($basename, '', $file['filepath']);
       $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']);
       unset($file['filepath']);
+      // Insert into the file_managed table.
       // Each fid should only be stored once in file_managed.
       db_merge('file_managed')
         ->key(array(
@@ -2766,26 +2798,34 @@ function system_update_7060(&$sandbox) {
         ))
         ->execute();
 
-      // Update the node field with the file URI.
-      $revision['file'][LANGUAGE_NONE][$delta] = $file;
-
       // Add the usage entry for the file.
       $file = (object) $file;
       file_usage_add($file, 'file', 'node', $revision['nid']);
+
+      // Update the node revision's upload file field with the file data.
+      $revision['file'][LANGUAGE_NONE][$delta] = array('fid' => $file->fid, 'display' => $file->display, 'description' => $file->description);
     }
 
-    // Insert the revision's files into the field_upload table.
+    // Write the revision's upload field data into the field_upload tables.
     $node = (object) $revision;
-    field_sql_storage_field_storage_write('node', $node, FIELD_STORAGE_INSERT, array($sandbox['field_id']));
+    _update_7000_field_sql_storage_write('node', $node->type, $node->nid, $node->vid, 'upload', $node->file);
 
     // Update our progress information for the batch update.
     $sandbox['progress']++;
     $sandbox['last_vid_processed'] = $vid;
   }
 
+  // If less than limit node revisions were processed, the update process is
+  // finished.
+  if (count($node_revisions) < $limit) {
+    $finished = TRUE;
+  }
+
+
   // If there's no max value then there's nothing to update and we're finished.
   if (empty($sandbox['max']) || isset($finished)) {
     db_drop_table('upload');
+    db_drop_table('system_update_7061');
     return t('Upload module has been migrated to File module.');
   }
   else {
@@ -2797,7 +2837,7 @@ function system_update_7060(&$sandbox) {
 /**
  * Replace 'system_list' index with 'bootstrap' index on {system}.
  */
-function system_update_7061() {
+function system_update_7062() {
   db_drop_index('system', 'bootstrap');
   db_drop_index('system', 'system_list');
   db_add_index('system', 'system_list', array('status', 'bootstrap', 'type', 'weight', 'name'));
