diff --git includes/file.inc includes/file.inc
index 26a6c41..bfd112d 100644
--- includes/file.inc
+++ includes/file.inc
@@ -1381,7 +1381,7 @@
  *   - source: Path to the file before it is moved.
  *   - destination: Path to the file after it is moved (same as 'uri').
  */
-function file_save_upload($source, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
+function file_save_upload(&$form_state, $source, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
   global $user;
   static $upload_cache;
 
@@ -1392,34 +1392,34 @@
   }
 
   // Make sure there's an upload to process.
-  if (empty($_FILES['files']['name'][$source])) {
+  if (empty($form_state['files']['name'][$source])) {
     return NULL;
   }
 
   // Check for file upload errors and return FALSE if a lower level system
   // error occurred. For a complete list of errors:
   // See http://php.net/manual/en/features.file-upload.errors.php.
-  switch ($_FILES['files']['error'][$source]) {
+  switch ($form_state['files']['error'][$source]) {
     case UPLOAD_ERR_INI_SIZE:
     case UPLOAD_ERR_FORM_SIZE:
-      drupal_set_message(t('The file %file could not be saved, because it exceeds %maxsize, the maximum allowed size for uploads.', array('%file' => $_FILES['files']['name'][$source], '%maxsize' => format_size(file_upload_max_size()))), 'error');
+      drupal_set_message(t('The file %file could not be saved, because it exceeds %maxsize, the maximum allowed size for uploads.', array('%file' => $form_state['files']['name'][$source], '%maxsize' => format_size(file_upload_max_size()))), 'error');
       return FALSE;
 
     case UPLOAD_ERR_PARTIAL:
     case UPLOAD_ERR_NO_FILE:
-      drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $_FILES['files']['name'][$source])), 'error');
+      drupal_set_message(t('The file %file could not be saved, because the upload did not complete.', array('%file' => $form_state['files']['name'][$source])), 'error');
       return FALSE;
 
     case UPLOAD_ERR_OK:
       // Final check that this is a valid upload, if it isn't, use the
       // default error handler.
-      if (is_uploaded_file($_FILES['files']['tmp_name'][$source])) {
+      if (is_uploaded_file($form_state['files']['tmp_name'][$source])) {
         break;
       }
 
     // Unknown error
     default:
-      drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $_FILES['files']['name'][$source])), 'error');
+      drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $form_state['files']['name'][$source])), 'error');
       return FALSE;
   }
 
@@ -1427,10 +1427,10 @@
   $file = new stdClass();
   $file->uid      = $user->uid;
   $file->status   = 0;
-  $file->filename = trim(basename($_FILES['files']['name'][$source]), '.');
-  $file->uri      = $_FILES['files']['tmp_name'][$source];
+  $file->filename = trim(basename($form_state['files']['name'][$source]), '.');
+  $file->uri      = $form_state['files']['tmp_name'][$source];
   $file->filemime = file_get_mimetype($file->filename);
-  $file->filesize = $_FILES['files']['size'][$source];
+  $file->filesize = $form_state['files']['size'][$source];
 
   $extensions = '';
   if (isset($validators['file_validate_extensions'])) {
@@ -1523,7 +1523,7 @@
   // directory. This overcomes open_basedir restrictions for future file
   // operations.
   $file->uri = $file->destination;
-  if (!move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->uri)) {
+  if (!move_uploaded_file($form_state['files']['tmp_name'][$source], $file->uri)) {
     form_set_error($source, t('File upload error. Could not move uploaded file.'));
     watchdog('file', 'Upload error. Could not move uploaded file %file to destination %destination.', array('%file' => $file->filename, '%destination' => $file->uri));
     return FALSE;
diff --git includes/form.inc includes/form.inc
index c0163ca..73d8489 100644
--- includes/form.inc
+++ includes/form.inc
@@ -282,6 +282,10 @@
     $form_state['input'] = $form_state['method'] == 'get' ? $_GET : $_POST;
   }
 
+  if (!isset($form_state['files'])) {
+    $form_state['files'] = !empty($_FILES['files']) ? $_FILES['files'] : array();
+  }
+
   if (isset($_SESSION['batch_form_state'])) {
     // We've been redirected here after a batch processing. The form has
     // already been processed, but needs to be rebuilt. See _batch_finished().
diff --git modules/aggregator/aggregator.admin.inc modules/aggregator/aggregator.admin.inc
index 08087af..ddf8b5c 100644
--- modules/aggregator/aggregator.admin.inc
+++ modules/aggregator/aggregator.admin.inc
@@ -284,7 +284,7 @@
  */
 function aggregator_form_opml_validate($form, &$form_state) {
   // If both fields are empty or filled, cancel.
-  if (empty($form_state['values']['remote']) == empty($_FILES['files']['name']['upload'])) {
+  if (empty($form_state['values']['remote']) == empty($form_state['files']['name']['upload'])) {
     form_set_error('remote', t('You must <em>either</em> upload a file or enter a URL.'));
   }
 
@@ -300,7 +300,7 @@
 function aggregator_form_opml_submit($form, &$form_state) {
   $data = '';
   $validators = array('file_validate_extensions' => array('opml xml'));
-  if ($file = file_save_upload('upload', $validators)) {
+  if ($file = file_save_upload($form_state, 'upload', $validators)) {
     $data = file_get_contents($file->uri);
   }
   else {
diff --git modules/file/file.module modules/file/file.module
index 4002701..68a0685 100644
--- modules/file/file.module
+++ modules/file/file.module
@@ -484,7 +484,7 @@
     $return = $input;
 
     // Uploads take priority over all other values.
-    if ($file = file_managed_file_save_upload($element)) {
+    if ($file = file_managed_file_save_upload($element, $form_state)) {
       $fid = $file->fid;
     }
     else {
@@ -605,13 +605,16 @@
  *
  * @param $element
  *   The FAPI element whose values are being saved.
+ * @param $form_state
+ *   The current state of the form.
+ *
  * @return
  *   The file object representing the file that was saved, or FALSE if no file
  *   was saved.
  */
-function file_managed_file_save_upload($element) {
+function file_managed_file_save_upload($element, &$form_state) {
   $upload_name = implode('_', $element['#parents']);
-  if (empty($_FILES['files']['name'][$upload_name])) {
+  if (empty($form_state['files']['name'][$upload_name])) {
     return FALSE;
   }
 
@@ -622,7 +625,7 @@
     return FALSE;
   }
 
-  if (!$file = file_save_upload($upload_name, $element['#upload_validators'], $destination)) {
+  if (!$file = file_save_upload($form_state, $upload_name, $element['#upload_validators'], $destination)) {
     watchdog('file', 'The file upload failed. %upload', array('%upload' => $upload_name));
     form_set_error($upload_name, t('The file in the !name field was unable to be uploaded.', array('!name' => $element['#title'])));
     return FALSE;
diff --git modules/locale/locale.admin.inc modules/locale/locale.admin.inc
index 3e4c6f1..8e19798 100644
--- modules/locale/locale.admin.inc
+++ modules/locale/locale.admin.inc
@@ -982,7 +982,7 @@
 function locale_translate_import_form_submit($form, &$form_state) {
   $validators = array('file_validate_extensions' => array('po'));
   // Ensure we have the file uploaded
-  if ($file = file_save_upload('file', $validators)) {
+  if ($file = file_save_upload($form_state, 'file', $validators)) {
 
     // Add language, if not yet supported
     drupal_static_reset('language_list');
diff --git modules/node/node.api.php modules/node/node.api.php
index 7353117..36afc19 100644
--- modules/node/node.api.php
+++ modules/node/node.api.php
@@ -1027,7 +1027,8 @@
  */
 function hook_prepare($node) {
   if ($file = file_check_upload($field_name)) {
-    $file = file_save_upload($field_name, _image_filename($file->filename, NULL, TRUE));
+    // FIXME there is no $form_state.
+    $file = file_save_upload($form_state, $field_name, _image_filename($file->filename, NULL, TRUE));
     if ($file) {
       if (!image_get_info($file->uri)) {
         form_set_error($field_name, t('Uploaded file is not a valid image'));
diff --git modules/simpletest/tests/file_test.module modules/simpletest/tests/file_test.module
index 2865a1f..ff95b9c 100644
--- modules/simpletest/tests/file_test.module
+++ modules/simpletest/tests/file_test.module
@@ -116,7 +116,7 @@
     $validators['file_validate_extensions'] = array($form_state['values']['extensions']);
   }
 
-  $file = file_save_upload('file_test_upload', $validators, $destination, $form_state['values']['file_test_replace']);
+  $file = file_save_upload($form_state, 'file_test_upload', $validators, $destination, $form_state['values']['file_test_replace']);
   if ($file) {
     $form_state['values']['file_test_upload'] = $file;
     drupal_set_message(t('File @filepath was uploaded.', array('@filepath' => $file->uri)));
@@ -133,7 +133,7 @@
 /**
  * Reset/initialize the history of calls to the file_* hooks.
  *
- * @see file_test_get_calls() 
+ * @see file_test_get_calls()
  * @see file_test_reset()
  */
 function file_test_reset() {
diff --git modules/system/system.admin.inc modules/system/system.admin.inc
index 92c534e..9edff5d 100644
--- modules/system/system.admin.inc
+++ modules/system/system.admin.inc
@@ -589,7 +589,7 @@
   $validators = array('file_validate_is_image' => array());
 
   // Check for a new uploaded logo.
-  $file = file_save_upload('logo_upload', $validators);
+  $file = file_save_upload($form_state, 'logo_upload', $validators);
   if (isset($file)) {
     // File upload was attempted.
     if ($file) {
@@ -605,7 +605,7 @@
   $validators = array('file_validate_extensions' => array('ico png gif jpg jpeg apng svg'));
 
   // Check for a new uploaded favicon.
-  $file = file_save_upload('favicon_upload', $validators);
+  $file = file_save_upload($form_state, 'favicon_upload', $validators);
   if (isset($file)) {
     // File upload was attempted.
     if ($file) {
diff --git modules/update/update.manager.inc modules/update/update.manager.inc
index b0def17..f865cf9 100644
--- modules/update/update.manager.inc
+++ modules/update/update.manager.inc
@@ -583,7 +583,7 @@
  * Validate the form for installing a new project via the update manager.
  */
 function update_manager_install_form_validate($form, &$form_state) {
-  if (!($form_state['values']['project_url'] XOR !empty($_FILES['files']['name']['project_upload']))) {
+  if (!($form_state['values']['project_url'] XOR !empty($form_state['files']['name']['project_upload']))) {
     form_set_error('project_url', t('You must either provide a URL or upload an archive file to install.'));
   }
 
@@ -618,10 +618,10 @@
       return;
     }
   }
-  elseif ($_FILES['files']['name']['project_upload']) {
+  elseif ($form_state['files']['name']['project_upload']) {
     $validators = array('file_validate_extensions' => array(archiver_get_extensions()));
     $field = 'project_upload';
-    if (!($finfo = file_save_upload($field, $validators, NULL, FILE_EXISTS_REPLACE))) {
+    if (!($finfo = file_save_upload($form_state, $field, $validators, NULL, FILE_EXISTS_REPLACE))) {
       // Failed to upload the file. file_save_upload() calls form_set_error() on
       // failure.
       return;
diff --git modules/user/user.module modules/user/user.module
index 358b4ce..7dce825 100644
--- modules/user/user.module
+++ modules/user/user.module
@@ -678,7 +678,7 @@
   );
 
   // Save the file as a temporary file.
-  $file = file_save_upload('picture_upload', $validators);
+  $file = file_save_upload($form_state, 'picture_upload', $validators);
   if ($file === FALSE) {
     form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
   }
