diff --git a/modules/file/file.admin.inc b/modules/file/file.admin.inc
index 5e5a134..2feea9b 100644
--- a/modules/file/file.admin.inc
+++ b/modules/file/file.admin.inc
@@ -16,8 +16,16 @@ function file_role_upload_list() {
   $rows = array();
 
   $default = array(
-    (object) array('rid' => -1, 'name' => 'user 1', 'extensions' => file_upload_extensions_user_1()),
-    (object) array('rid' => 0, 'name' => 'default', 'extensions' => file_upload_extensions_default()),
+    (object) array(
+      'rid' => -1,
+      'name' => 'user 1',
+      'extensions' => file_upload_extensions_user_1(),
+    ),
+    (object) array(
+      'rid' => 0,
+      'name' => 'default',
+      'extensions' => file_upload_extensions_default(),
+    ),
   );
  
   $roles = db_query('SELECT rid, name FROM {role}')->fetchAll();
@@ -27,10 +35,10 @@ function file_role_upload_list() {
   foreach ($roles as $role) {
     if ($role->rid > 0) {
       // Explicitly tell value is not set
-      $extensions = variable_get("upload_extensions_" . $role->rid, '- ' . t('default') . ' -');
+      $extensions = variable_get('upload_extensions_' . $role->rid, '- ' . t('default') . ' -');
     }
     else {
-    	$extensions = $role->extensions;
+      $extensions = $role->extensions;
     }
     $rows[] = array(
       $role->rid,
@@ -55,16 +63,16 @@ function file_role_upload_list() {
  * Category edit page.
  */
 function file_role_upload_edit_form($form, &$form_state, $rid) {
-  $args=func_get_args();
+  $args = func_get_args();
 
   $rid = isset($form_state['values']['rid']) ? $form_state['values']['rid'] : $rid;
   
   $var_name = _file_role_extensions_var_name($rid);
-  if ($rid==0) {
+  if ($rid == 0) {
     $current = file_upload_extensions_default();
   }
-  else if ($rid==-1) {
-  	$current = file_upload_extensions_user_1();  	
+  else if ($rid == -1) {
+    $current = file_upload_extensions_user_1();
   }
   else {
     $current = variable_get("upload_extensions_" . $rid, file_upload_extensions_default());
@@ -83,7 +91,10 @@ function file_role_upload_edit_form($form, &$form_state, $rid) {
     '#value' => $rid,
   );
  
-  $form['actions'] = array('#type' => 'container', '#attributes' => array('class' => array('form-actions')));
+  $form['actions'] = array(
+    '#type' => 'container',
+    '#attributes' => array('class' => array('form-actions')),
+  );
   $form['actions']['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Save'),
@@ -108,7 +119,7 @@ function file_role_upload_edit_form_submit($form, &$form_state) {
   $exts = $form_state['values']['file_extensions'];
  
   $var_name = _file_role_extensions_var_name($rid);
-  variable_set( $var_name, $exts);
+  variable_set($var_name, $exts);
 
   drupal_set_message(t('Upload file extensions for %role has been saved.', array('%role' => _file_role_name($rid))));
 
@@ -143,10 +154,10 @@ function file_role_upload_delete_form_submit($form, &$form_state) {
   $var_name = _file_role_extensions_var_name($rid);
   variable_del($var_name);
   
-  if ($rid==0) {
+  if ($rid == 0) {
     variable_set($var_name, file_upload_extensions_default());
   }
-  else if ($rid==-1) {
+  else if ($rid == -1) {
     variable_set($var_name, file_upload_extensions_user_1());
   }
   
@@ -157,24 +168,24 @@ function file_role_upload_delete_form_submit($form, &$form_state) {
 }
 
 function _file_role_name($rid) {
-	if ($rid==0) {
-		return t('Default values');
-	}
-	else if ($rid==-1) {
-		return t('user 1');
-	}
-	$role = db_query('SELECT name FROM {role} WHERE rid=:rid', array(':rid' => $rid))->fetchAssoc();
-	return t($role['name']);
+  if ($rid == 0) {
+    return t('Default values');
+  }
+  else if ($rid == -1) {
+    return t('user 1');
+  }
+  $role = db_query('SELECT name FROM {role} WHERE rid=:rid', array(':rid' => $rid))->fetchAssoc();
+  return t($role['name']);
 }
 
 function _file_role_extensions_var_name($rid) {
-	if ($rid > 0) {
-    return "upload_extensions_" .$rid;
+  if ($rid > 0) {
+    return 'upload_extensions_' . $rid;
   }
-  else if ($rid==0) {
+  else if ($rid == 0) {
     return 'upload_extensions_default';
   }
-  else if ($rid==-1) {
+  else if ($rid == -1) {
     return 'upload_extensions_user_1';
   }
-}
\ No newline at end of file
+}
diff --git a/modules/file/file.info b/modules/file/file.info
index 675c26b..8ada6d4 100644
--- a/modules/file/file.info
+++ b/modules/file/file.info
@@ -5,6 +5,7 @@ package = Core
 version = VERSION
 core = 7.x
 files[] = file.module
+files[] = file.admin.inc
 files[] = file.field.inc
 files[] = file.install
 files[] = tests/file.test
diff --git a/modules/file/file.module b/modules/file/file.module
index c8b1fd0..7222b7f 100644
--- a/modules/file/file.module
+++ b/modules/file/file.module
@@ -49,10 +49,59 @@ function file_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
+  $items['admin/config/file_role_upload'] = array(
+    'title' => 'File upload settings',
+    'description' => 'Set the extension per role.',
+    'access arguments' => array('administer site'),
+    'file' => 'file.admin.inc',
+  );
+  $items['admin/config/file_role_upload/list'] = array(
+    'title' => 'File upload extensions',
+    'description' => 'Set the extension per role.',
+    'page callback' => 'file_role_upload_list',
+    'access arguments' => array('administer site'),
+    'file' => 'file.admin.inc',
+  );
+  $items['admin/config/file_role_upload/edit/%'] = array(
+    'title' => 'Edit role upload settings',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('file_role_upload_edit_form', 4),
+    'type' => MENU_CALLBACK,
+    'access arguments' => array('administer site'),
+    'file' => 'file.admin.inc',
+  );
+  $items['admin/config/file_role_upload/delete/%'] = array(
+    'title' => 'Delete role upload settings',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('file_role_upload_delete_form', 4),
+    'type' => MENU_CALLBACK,
+    'access arguments' => array('administer site'),
+    'file' => 'file.admin.inc',
+  );
 
   return $items;
 }
 
+function file_upload_extensions_default() {
+  return variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp');
+}
+
+function file_upload_extensions_user_1() {
+  return variable_get('upload_extensions_user_1', 'zip tgz tar gz bz2');
+}
+
+function file_upload_allowed_extensions($account) {
+  $extensions = '';
+  $extensions_default = file_upload_extensions_default();
+  foreach ($account->roles as $rid => $name) {
+    $extensions .= ' ' . variable_get("upload_extensions_$rid", $extensions_default);
+  }
+  if ($account->uid == 1) {
+    $extensions .= ' ' . file_upload_extensions_user_1();
+  }
+  return $extensions;
+}
+
 /**
  * Implements hook_element_info().
  *
diff --git a/modules/simpletest/tests/filetransfer.test b/modules/simpletest/tests/filetransfer.test
index b9a79f7..aa1bbed 100644
--- a/modules/simpletest/tests/filetransfer.test
+++ b/modules/simpletest/tests/filetransfer.test
@@ -12,7 +12,7 @@ class FileTranferTest extends DrupalWebTestCase {
     return array(
       'name' => 'FileTransfer unit tests',
       'description' => 'Test that the jail is respected and that protocols using recursive file move operations work.',
-      'group' => 'System'
+      'group' => 'System',
     );
   }
 
@@ -89,6 +89,54 @@ class FileTranferTest extends DrupalWebTestCase {
   }
 }
 
+class FileTransferUploadTest extends DrupalWebTestCase {
+  function getInfo() {
+    return array(
+      'name' => 'FileTransfer upload tests',
+      'description' => 'Tests that the upload interface can install modules or themes.',
+      'group' => 'System',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('update');
+    $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer software updates', 'administer modules'));
+    $this->drupalLogin($this->admin_user);
+  }
+
+  function testTarballUpload() {
+    // Make a really small test module.
+    $info = "name = File transfer test\ncore = 7.x\nfiles[] = filetransfer_test.module";
+    $module = '<?php
+      function filetransfer_test_enable() {
+        variable_set("filetransfer_test_success", TRUE);
+      }
+    ';
+    $path = 'temporary://filetransfer_test/';
+
+    // Write the module to files.
+    drupal_mkdir($path);
+    $info_file = file_unmanaged_save_data($info, $path .'filetransfer_test.info', FILE_EXISTS_REPLACE);
+    $module_file = file_unmanaged_save_data($module, $path .'filetransfer_test.module', FILE_EXISTS_REPLACE);
+
+    // Roll a tarball of the module.
+    $tar = new Archive_Tar(file_directory_path('temporary') .'/filetransfer_test.tar.gz', 'gz');
+    $tar->createModify($path, '', 'temporary://');
+
+    // Attempt to upload the module.
+    $this->drupalPost('admin/reports/updates/install', array('files[project_upload]' => $tar->_tarname), t('Install'));
+    $this->clickLink(t('Enable newly added modules in !project', array('!project' => 'File transfer test')));
+    $this->drupalPost('admin/modules', array('modules[Other][filetransfer_test][enable]' => 1), t('Save configuration'));
+    $this->assertTrue(variable_get('filetransfer_test_success', FALSE), t('The module was installed.'));
+  }
+
+  function tearDown() {
+    // Delete the module as it as placed where simpletest does not clean up.
+    file_unmanaged_delete_recursive(drupal_get_path('module', 'filetransfer_test'));
+    parent::tearDown();
+  }
+}
+
 /**
  * Mock FileTransfer object for test case.
  */
