=== modified file 'modules/system/system.install'
--- modules/system/system.install	2010-02-26 06:39:13 +0000
+++ modules/system/system.install	2010-03-01 13:52:58 +0000
@@ -2254,28 +2254,120 @@
 /**
  * Migrate upload module files to the new {file} table.
  */
-function system_update_7035() {
+function system_update_7035(&$sandbox) {
   if (!db_table_exists('upload')) {
     return;
   }
 
-  // The old {files} tables still exists.  We migrate core data from upload
-  // module, but any contrib module using it will need to do its own update.
-  $result = db_query('SELECT f.fid, uid, filename, filepath AS uri, filemime, filesize, status, timestamp FROM {files} f INNER JOIN {upload} u ON u.fid = f.fid', array(), array('fetch' => PDO::FETCH_ASSOC));
-
-  // We will convert filepaths to uri using the default schmeme
-  // and stripping off the existing file directory path.
-  $basename = variable_get('file_directory_path', conf_path() . '/files');
-  $scheme = variable_get('file_default_scheme', 'public') . '://';
-  $fids = array();
-  // TODO: does this function need to run in batch mode, or should we use a multi-insert?
-  foreach ($result as $file) {
-    $file['uri'] = $scheme . str_replace($basename, '', $file['uri']);
-    $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']);
-    db_insert('file')->fields($file)->execute();
-    $fids[] = $file['fid'];
-  }
-  // TODO: delete the found fids from {files}?
+  $field = field_info_field('files');
+
+  if (!isset($sandbox['progress'])) {
+    if (empty($field)) {
+      $field = array(
+        'field_name' => 'files',
+        'type' => 'file',
+        'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+        'settings' => array(
+          'display_field' => 1,
+          'display_default' => variable_get('upload_list_default', 1),
+          'uri_scheme' => variable_get('file_default_scheme', 'public'),
+        ),
+      );
+      $field = field_create_field($field);
+    }
+
+    $node_types = node_type_get_types();
+
+    foreach ($node_types as $type) {
+      $instance = field_info_instance('node', 'files', $type->type);
+
+      if (variable_get('upload_' . $type->type, TRUE) && empty($instance)) {
+        $upload_extensions_default = variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp');
+        $upload_uploadsize_default = variable_get('upload_uploadsize_default', 1);
+
+        $instance = array(
+          'field_name' => 'files',
+          'object_type' => 'node',
+          'bundle' => $type->type,
+          'label' => 'File attachments',
+          'settings' => array(
+            'file_extensions' => $upload_extensions_default,
+            'max_filesize' => $upload_uploadsize_default,
+            'description_field' => 1,
+          ),
+        );
+
+        field_create_instance($instance);
+      }
+    }
+
+    $sandbox['progress'] = 0;
+    $sandbox['current_fid'] = 0;
+    $sandbox['current_vid'] = 0;
+    $sandbox['max'] = db_query("SELECT COUNT(DISTINCT fid) FROM {upload}")->fetchField();
+  }
+  else {
+    $limit = 200;
+
+    // The old {files} tables still exists.  We migrate core data from upload
+    // module, but any contrib module using it will need to do its own update.
+    $result = db_query_range('SELECT u.nid, u.vid, n.type, u.fid, uid, filename, filepath AS uri, filemime, filesize, status, timestamp FROM {files} AS f INNER JOIN {upload} AS u ON u.fid = f.fid INNER JOIN {node} AS n ON u.nid = n.nid WHERE f.fid > :fid OR (f.fid = :current_fid AND u.vid > :vid) ORDER BY u.fid, u.vid', 0, $limit, array(':fid' => $sandbox['current_fid'], ':current_fid' => $sandbox['current_fid'], ':vid' => $sandbox['current_vid']), array('fetch' => PDO::FETCH_ASSOC));
+
+    // We will convert filepaths to uri using the default scheme
+    // and stripping off the existing file directory path.
+    $basename = variable_get('file_directory_path', conf_path() . '/files');
+    $scheme = variable_get('file_default_scheme', 'public') . '://';
+
+    // Keep track of how many files each node has across invocations.
+    $sandbox['deltas'] = array();
+    // Don't need to keep the node data across invocations because we are only
+    // inserting data.
+    $nodes = array();
+
+    foreach ($result as $file) {
+      if (!isset($nodes[$file['vid']])) {
+        $node = (object) array(
+          'nid' => $file['nid'],
+          'vid' => $file['vid'],
+          'type' => $file['type'],
+          'uploads' => array(),
+        );
+        $deltas[$node->vid] = 0;
+      }
+      else {
+        $node = $nodes[$file['vid']];
+      }
+
+      // Several node revisions may have the same file. Only copy file data once.
+      if ($sandbox['current_fid'] != $file['fid']) {
+        // Hide node fields from the insert query.
+        unset($file['nid']);
+        unset($file['vid']);
+        unset($file['type']);
+
+        $file['uri'] = $scheme . str_replace($basename, '', $file['uri']);
+        $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']);
+        $new_fid = db_insert('file')->fields($file)->execute();
+      }
+
+      $node->files[LANGUAGE_NONE][$sandbox['deltas'][$node->vid]++] = $file;
+
+      $sandbox['progress']++;
+      $sandbox['current_fid'] = $file['fid'];
+      $sandbox['current_vid'] = $node->vid;
+      $sandbox['message'] = check_plain($file['filename']);
+    }
+
+    foreach ($nodes as $node) {
+      // This is a core update and no contrib modules are enabled yet, so
+      // we can assume default field storage for a faster update.
+      field_sql_storage_field_storage_write('node', $node, FIELD_STORAGE_INSERT, array($field['id']));
+    }
+  }
+
+  if ($sandbox['progress'] < $sandbox['max']) {
+    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+  }
 }
 
 /**

