? .DS_Store
? .cache
? .project
? .settings
? drupal.hook-file.patch
? empty
? logs
? modules/.DS_Store
? sites/all/modules
? sites/default/files
? sites/default/settings.php
? sites/default/test
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.770
diff -u -p -r1.770 common.inc
--- includes/common.inc	30 May 2008 17:41:51 -0000	1.770
+++ includes/common.inc	30 May 2008 20:44:18 -0000
@@ -1782,7 +1782,7 @@ function drupal_build_css_cache($types, 
     $data = implode('', $matches[0]) . $data;
 
     // Create the CSS file.
-    file_save_data($data, $csspath . '/' . $filename, FILE_EXISTS_REPLACE);
+    file_save_data_plain($data, $csspath . '/' . $filename, FILE_EXISTS_REPLACE);
   }
   return $csspath . '/' . $filename;
 }
@@ -1883,7 +1883,7 @@ function _drupal_load_stylesheet($matche
  * Delete all cached CSS files.
  */
 function drupal_clear_css_cache() {
-  file_scan_directory(file_create_path('css'), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE);
+  file_scan_directory(file_create_path('css'), '.*', array('.', '..', 'CVS'), 'file_delete_plain', TRUE);
 }
 
 /**
@@ -2241,7 +2241,7 @@ function drupal_build_js_cache($files, $
     }
 
     // Create the JS file.
-    file_save_data($contents, $jspath . '/' . $filename, FILE_EXISTS_REPLACE);
+    file_save_data_plain($contents, $jspath . '/' . $filename, FILE_EXISTS_REPLACE);
   }
 
   return $jspath . '/' . $filename;
@@ -2251,7 +2251,7 @@ function drupal_build_js_cache($files, $
  * Delete all cached JS files.
  */
 function drupal_clear_js_cache() {
-  file_scan_directory(file_create_path('js'), '.*', array('.', '..', 'CVS'), 'file_delete', TRUE);
+  file_scan_directory(file_create_path('js'), '.*', array('.', '..', 'CVS'), 'file_delete_plain', TRUE);
   variable_set('javascript_parsed', array());
 }
 
Index: includes/file.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/file.inc,v
retrieving revision 1.125
diff -u -p -r1.125 file.inc
--- includes/file.inc	26 May 2008 17:12:54 -0000	1.125
+++ includes/file.inc	30 May 2008 20:44:18 -0000
@@ -39,7 +39,8 @@ define('FILE_CREATE_DIRECTORY', 1);
 define('FILE_MODIFY_PERMISSIONS', 2);
 
 /**
- * Flag for dealing with existing files: Append number until filename is unique.
+ * Flag for dealing with existing files: Append number until filename is
+ * unique.
  */
 define('FILE_EXISTS_RENAME', 0);
 
@@ -77,7 +78,8 @@ define('FILE_STATUS_PERMANENT', 1);
  * @return A string containing a URL that can be used to download the file.
  */
 function file_create_url($path) {
-  // Strip file_directory_path from $path. We only include relative paths in urls.
+  // Strip file_directory_path from $path. We only include relative paths in
+  // URLs.
   if (strpos($path, file_directory_path() . '/') === 0) {
     $path = trim(substr($path, strlen(file_directory_path())), '\\/');
   }
@@ -93,28 +95,30 @@ function file_create_url($path) {
  * Make sure the destination is a complete path and resides in the file system
  * directory, if it is not prepend the file system directory.
  *
- * @param $dest A string containing the path to verify. If this value is
+ * @param $destination A string containing the path to verify. If this value is
  *   omitted, Drupal's 'files' directory will be used.
  * @return A string containing the path to file, with file system directory
  *   appended if necessary, or FALSE if the path is invalid (i.e. outside the
  *   configured 'files' or temp directories).
  */
-function file_create_path($dest = 0) {
+function file_create_path($destination = 0) {
   $file_path = file_directory_path();
-  if (!$dest) {
+  if (!$destination) {
     return $file_path;
   }
-  // file_check_location() checks whether the destination is inside the Drupal files directory.
-  if (file_check_location($dest, $file_path)) {
-    return $dest;
-  }
-  // check if the destination is instead inside the Drupal temporary files directory.
-  else if (file_check_location($dest, file_directory_temp())) {
-    return $dest;
+  // file_check_location() checks whether the destination is inside the Drupal
+  // files directory.
+  if (file_check_location($destination, $file_path)) {
+    return $destination;
+  }
+  // Check if the destination is instead inside the Drupal temporary files
+  // directory.
+  else if (file_check_location($destination, file_directory_temp())) {
+    return $destination;
   }
   // Not found, try again with prefixed directory path.
-  else if (file_check_location($file_path . '/' . $dest, $file_path)) {
-    return $file_path . '/' . $dest;
+  else if (file_check_location($file_path . '/' . $destination, $file_path)) {
+    return $file_path . '/' . $destination;
   }
   // File not found.
   return FALSE;
@@ -233,88 +237,119 @@ function file_check_location($source, $d
 }
 
 /**
- * Copies a file to a new location. This is a powerful function that in many ways
+ * Copy a file to a new location and adds a file record to the database.
+ *
+ * This function should be used when manipulating files that have records
+ * stored in the database. This is a powerful function that in many ways
  * performs like an advanced version of copy().
- * - Checks if $source and $dest are valid and readable/writable.
- * - Performs a file copy if $source is not equal to $dest.
- * - If file already exists in $dest either the call will error out, replace the
- *   file or rename the file based on the $replace parameter.
- *
- * @param $source A string specifying the file location of the original file.
- *   This parameter will contain the resulting destination filename in case of
- *   success.
- * @param $dest A string containing the directory $source should be copied to.
- *   If this value is omitted, Drupal's 'files' directory will be used.
- * @param $replace Replace behavior when the destination file already exists.
- *   - FILE_EXISTS_REPLACE - Replace the existing file
- *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique
+ * - Checks if $source and $destination are valid and readable/writable.
+ * - Performs a file copy if $source is not equal to $destination.
+ * - If file already exists in $destination either the call will error out,
+ *   replace the file or rename the file based on the $replace parameter.
+ * - Adds the new file to the files database. If the source file is a 
+ *   temporary file, the resulting file will also be a temporary file.
+ *   @see file_save_upload about temporary files.
+ *
+ * @param $source
+ *   A file object.
+ * @param $destination 
+ *   A string containing the directory $source should be copied to. If this 
+ *   value is omitted, Drupal's 'files' directory will be used.
+ * @param $replace 
+ *   Replace behavior when the destination file already exists:
+ *   - FILE_EXISTS_REPLACE - Replace the existing file.
+ *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
+ *                          unique.
  *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
- * @return True for success, FALSE for failure.
+ * @return
+ *   File object if the copy is successful, or FALSE in the event of an error.
+ *
+ * @see file_copy_plain()
  */
-function file_copy(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
-  $dest = file_create_path($dest);
-
-  $directory = $dest;
-  $basename = file_check_path($directory);
-
-  // Make sure we at least have a valid directory.
-  if ($basename === FALSE) {
-    $source = is_object($source) ? $source->filepath : $source;
-    drupal_set_message(t('The selected file %file could not be uploaded, because the destination %directory is not properly configured.', array('%file' => $source, '%directory' => $dest)), 'error');
-    watchdog('file system', 'The selected file %file could not be uploaded, because the destination %directory could not be found, or because its permissions do not allow the file to be written.', array('%file' => $source, '%directory' => $dest), WATCHDOG_ERROR);
-    return 0;
-  }
-
-  // Process a file upload object.
-  if (is_object($source)) {
-    $file = $source;
-    $source = $file->filepath;
-    if (!$basename) {
-      $basename = $file->filename;
+function file_copy($source, $destination = 0, $replace = FILE_EXISTS_RENAME) {
+  if ($result = file_copy_plain($source->filepath, $destination, $replace)) {
+    $file = clone $source;
+    $file->fid      = NULL;
+    $file->filename = basename($result);
+    $file->filepath = $result;
+    if ($file = file_save($file)) {
+      module_invoke_all('file_copy', $file, $source);
+      return $file;
     }
   }
+  return FALSE; 
+}
 
+/**
+ * Copy a file to a new location without saving a record in the database.
+ *
+ * This is a powerful function that in many ways performs like an advanced
+ * version of copy().
+ * - Checks if $source and $destination are valid and readable/writable.
+ * - Performs a file copy if $source is not equal to $destination.
+ * - If file already exists in $destination either the call will error out,
+ *   replace the file or rename the file based on the $replace parameter.
+ *
+ * @param $source
+ *   A string specifying the file location of the original file.
+ * @param $destination
+ *   A string containing the directory $source should be copied to. If this 
+ *   value is omitted, Drupal's 'files' directory will be used.
+ * @param $replace 
+ *   Replace behavior when the destination file already exists:
+ *   - FILE_EXISTS_REPLACE - Replace the existing file.
+ *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
+ *                          unique.
+ *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
+ * @return
+ *   The path to the new file, or FALSE in the event of an error.
+ *
+ * @see file_copy()
+ */
+function file_copy_plain($source, $destination = 0, $replace = FILE_EXISTS_RENAME) {
   $source = realpath($source);
   if (!file_exists($source)) {
     drupal_set_message(t('The selected file %file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $source)), 'error');
-    return 0;
+    return FALSE;
   }
+  
+  $destination = file_create_path($destination);
+  $directory = $destination;
+  $basename = file_check_path($directory);
 
-  // If the destination file is not specified then use the filename of the source file.
+  // Make sure we at least have a valid directory.
+  if ($basename === FALSE) {
+    drupal_set_message(t('The selected file %file could not be copied, because the destination %directory is not properly configured.', array('%file' => $source, '%directory' => $destination)), 'error');
+    return FALSE;
+  }
+
+  // If the destination file is not specified then use the filename of the
+  // source file.
   $basename = $basename ? $basename : basename($source);
-  $dest = $directory . '/' . $basename;
+  $destination = $directory . '/' . $basename;
 
-  // Make sure source and destination filenames are not the same, makes no sense
-  // to copy it if they are. In fact copying the file will most likely result in
-  // a 0 byte file. Which is bad. Real bad.
-  if ($source != realpath($dest)) {
-    if (!$dest = file_destination($dest, $replace)) {
+  // Make sure source and destination filenames are not the same, makes no
+  // sense to copy it if they are. In fact copying the file will most likely
+  // result in a 0 byte file. Which is bad. Real bad.
+  if ($source != realpath($destination)) {
+    if (!$destination = file_destination($destination, $replace)) {
       drupal_set_message(t('The selected file %file could not be copied, because a file by that name already exists in the destination.', array('%file' => $source)), 'error');
       return FALSE;
     }
 
-    if (!@copy($source, $dest)) {
+    if (!@copy($source, $destination)) {
       drupal_set_message(t('The selected file %file could not be copied.', array('%file' => $source)), 'error');
-      return 0;
+      return FALSE;
     }
 
     // Give everyone read access so that FTP'd users or
     // non-webserver users can see/read these files,
     // and give group write permissions so group members
     // can alter files uploaded by the webserver.
-    @chmod($dest, 0664);
+    @chmod($destination, 0664);
   }
 
-  if (isset($file) && is_object($file)) {
-    $file->filename = $basename;
-    $file->filepath = $dest;
-    $source = $file;
-  }
-  else {
-    $source = $dest;
-  }
-
-  return 1; // Everything went ok.
+  return $destination;
 }
 
 /**
@@ -323,9 +358,9 @@ function file_copy(&$source, $dest = 0, 
  *
  * @param $destination A string specifying the desired path.
  * @param $replace Replace behavior when the destination file already exists.
- *   - FILE_EXISTS_REPLACE - Replace the existing file
+ *   - FILE_EXISTS_REPLACE - Replace the existing file.
  *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
- *     unique
+ *                          unique.
  *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
  * @return The destination file path or FALSE if the file already exists and
  *   FILE_EXISTS_ERROR was specified.
@@ -333,6 +368,10 @@ function file_copy(&$source, $dest = 0, 
 function file_destination($destination, $replace) {
   if (file_exists($destination)) {
     switch ($replace) {
+      case FILE_EXISTS_REPLACE:
+        // Do nothing here, we want to overwrite the existing file.
+        break;
+
       case FILE_EXISTS_RENAME:
         $basename = basename($destination);
         $directory = dirname($destination);
@@ -348,35 +387,68 @@ function file_destination($destination, 
 }
 
 /**
- * Moves a file to a new location.
- * - Checks if $source and $dest are valid and readable/writable.
- * - Performs a file move if $source is not equal to $dest.
- * - If file already exists in $dest either the call will error out, replace the
- *   file or rename the file based on the $replace parameter.
- *
- * @param $source A string specifying the file location of the original file.
- *   This parameter will contain the resulting destination filename in case of
- *   success.
- * @param $dest A string containing the directory $source should be copied to.
- *   If this value is omitted, Drupal's 'files' directory will be used.
- * @param $replace Replace behavior when the destination file already exists.
- *   - FILE_EXISTS_REPLACE - Replace the existing file
- *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique
+ * Move a file to a new location and update the file's database entry.
+ *
+ * Moving a file is performed by copying the file to the new location and then
+ * deleting the original. 
+ * - Checks if $source and $destination are valid and readable/writable.
+ * - Performs a file move if $source is not equal to $destination.
+ * - If file already exists in $destination either the call will error out,
+ *   replace the file or rename the file based on the $replace parameter.
+ * - Adds the new file to the files database.
+ *
+ * @param $source
+ *   A file object.
+ * @param $destination
+ *   A string containing the directory $source should be copied to. If this 
+ *   value is omitted, Drupal's 'files' directory will be used.
+ * @param $replace 
+ *   Replace behavior when the destination file already exists:
+ *   - FILE_EXISTS_REPLACE - Replace the existing file.
+ *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
+ *                          unique.
  *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
- * @return True for success, FALSE for failure.
+ * @return
+ *   Resulting file object for success, or FALSE in the event of an error.
  */
-function file_move(&$source, $dest = 0, $replace = FILE_EXISTS_RENAME) {
-  $path_original = is_object($source) ? $source->filepath : $source;
-
-  if (file_copy($source, $dest, $replace)) {
-    $path_current = is_object($source) ? $source->filepath : $source;
+function file_move($source, $destination = 0, $replace = FILE_EXISTS_RENAME) {
+  if ($result = file_move_plain($source->filepath, $destination, $replace)) {
+    $file = clone $source;
+    $file->filename = basename($result);
+    $file->filepath = $result;
+    if ($file = file_save($file)) {
+      module_invoke_all('file_move', $file, $source);
+      return $file;
+    }
+    drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => $source->filepath)), 'error');
+  }
+  return FALSE;
+}
 
-    if ($path_original == $path_current || file_delete($path_original)) {
-      return 1;
+/**
+ * Move a file to a new location.
+ *
+ * @param $source
+ *   A string specifying the file location of the original file.
+ * @param $destination
+ *   A string containing the directory $source should be copied to. If this 
+ *   value is omitted, Drupal's 'files' directory will be used.
+ * @param $replace 
+ *   Replace behavior when the destination file already exists:
+ *   - FILE_EXISTS_REPLACE - Replace the existing file.
+ *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
+ *                          unique.
+ *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
+ * @return
+ *   The filepath of the moved file, or FALSE in the event of an error.
+ */
+function file_move_plain($source, $destination = 0, $replace = FILE_EXISTS_RENAME) {
+  if ($result = file_copy_plain($source, $destination, $replace)) {
+    if (!file_delete_plain($source)) {
+      $result = FALSE;
     }
-    drupal_set_message(t('The removal of the original file %file has failed.', array('%file' => $path_original)), 'error');
   }
-  return 0;
+  return $result;
 }
 
 /**
@@ -441,9 +513,9 @@ function file_unmunge_filename($filename
  * @return
  */
 function file_create_filename($basename, $directory) {
-  $dest = $directory . '/' . $basename;
+  $destination = $directory . '/' . $basename;
 
-  if (file_exists($dest)) {
+  if (file_exists($destination)) {
     // Destination file already exists, generate an alternative.
     if ($pos = strrpos($basename, '.')) {
       $name = substr($basename, 0, $pos);
@@ -455,45 +527,102 @@ function file_create_filename($basename,
 
     $counter = 0;
     do {
-      $dest = $directory . '/' . $name . '_' . $counter++ . $ext;
-    } while (file_exists($dest));
+      $destination = $directory . '/' . $name . '_' . $counter++ . $ext;
+    } while (file_exists($destination));
   }
 
-  return $dest;
+  return $destination;
+}
+
+/**
+ * Delete a file and its database record.
+ *
+ * @param $path 
+ *   A file object.
+ * @param $force
+ *   Boolean indicating that the file should be deleted even if
+ *   hook_file_references() reports that the file is in use.
+ * @return mixed 
+ *   TRUE for success, Array for reference count block, or FALSE in the event
+ *   of an error.
+ *
+ * @see hook_file_references()
+ */
+function file_delete($file, $force = FALSE) {
+  // If any module returns a value from the reference hook, the 
+  // file will not be deleted from Drupal, but file_delete will
+  // return a populated array that tests as TRUE.
+  if (!$force && ($references = module_invoke_all('file_references', $file))) {
+    return $references;
+  }
+
+  // Let other modules clean up on delete.
+  module_invoke_all('file_delete', $file);
+ 
+  // Make sure the file is deleted before removing its row from the 
+  // database, so UIs can still find the file in the database.
+  if (file_delete_plain($file->filepath)) {
+    db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
+    return TRUE;
+  }
+  return FALSE;
 }
 
 /**
  * Delete a file.
  *
- * @param $path A string containing a file path.
- * @return TRUE for success, FALSE for failure.
+ * This function should be used when the file to be deleted does not have an
+ * entry recorded in the files table.
+ *
+ * @param $path
+ *   A string containing a file path.
+ * @return
+ *   TRUE for success or path does not exist, or FALSE in the event of an
+ *   error.
  */
-function file_delete($path) {
+function file_delete_plain($path) {
   if (is_file($path)) {
     return unlink($path);
   }
+  if (is_dir($path)) {
+    watchdog('file', t('%path is a directory and cannot be removed with file_delete_plain.', array('%path' => $path)), WATCHDOG_ERROR);
+    return FALSE;
+  } 
+  // Return TRUE for non-existant file, but log that nothing was actually 
+  // deleted, as the intended result of file_delete_plain is in fact the 
+  // current state.
+  if (!file_exists($path)) {
+    watchdog('file', t('The file %path was not deleted, because it does not exist.', array('%path' => $path)), WATCHDOG_NOTICE);
+    return TRUE;
+  }
+  return FALSE;
 }
 
 /**
  * Determine total disk space used by a single user or the whole filesystem.
  *
  * @param $uid
- *   An optional user id. A NULL value returns the total space used
- *   by all files.
+ *   Optional. A user id, specifying NULL returns the total space used by all 
+ *   non-temporary files.
+ * @param $status
+ *   Optional. File Status to return. Combine with a bitwise OR(|) to return
+ *   multiple statuses. The default status is FILE_STATUS_PERMANENT.
+ * @return
+ *   An integer containing the number of bytes used.
  */
-function file_space_used($uid = NULL) {
+function file_space_used($uid = NULL, $status = FILE_STATUS_PERMANENT) {
   if (isset($uid)) {
-    return (int) db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE uid = %d', $uid));
+    return (int)db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE uid = %d AND status & %d', $uid, $status));
   }
-  return (int) db_result(db_query('SELECT SUM(filesize) FROM {files}'));
+  return (int)db_result(db_query('SELECT SUM(filesize) FROM {files} WHERE status & %d', $status));
 }
 
 /**
  * Saves a file upload to a new location. The source file is validated as a
  * proper upload and handled as such.
  *
- * The file will be added to the files table as a temporary file. Temporary files
- * are periodically cleaned. To make the file permanent file call
+ * The file will be added to the files table as a temporary file. Temporary
+ * files are periodically cleaned. To make the file permanent file call
  * file_set_status() to change its status.
  *
  * @param $source
@@ -505,7 +634,7 @@ function file_space_used($uid = NULL) {
  *   functions should return an array of error messages, an empty array
  *   indicates that the file passed validation. The functions will be called in
  *   the order specified.
- * @param $dest
+ * @param $destination
  *   A string containing the directory $source should be copied to. If this is
  *   not provided or is not writable, the temporary directory will be used.
  * @param $replace
@@ -513,25 +642,26 @@ function file_space_used($uid = NULL) {
  *   destination directory should overwritten. A false value will generate a
  *   new, unique filename in the destination directory.
  * @return
- *   An object containing the file information, or 0 in the event of an error.
+ *   An object containing the file information, or FALSE in the event of an 
+ *   error.
  */
-function file_save_upload($source, $validators = array(), $dest = FALSE, $replace = FILE_EXISTS_RENAME) {
+function file_save_upload($source, $validators = array(), $destination = FALSE, $replace = FILE_EXISTS_RENAME) {
   global $user;
   static $upload_cache;
 
-  // Add in our check of the the file name length.
-  $validators['file_validate_name_length'] = array();
-
   // Return cached objects without processing since the file will have
   // already been processed and the paths in _FILES will be invalid.
   if (isset($upload_cache[$source])) {
     return $upload_cache[$source];
   }
 
+  // Add in our check of the the file name length.
+  $validators['file_validate_name_length'] = array();
+
   // If a file was uploaded, process it.
   if (isset($_FILES['files']) && $_FILES['files']['name'][$source] && is_uploaded_file($_FILES['files']['tmp_name'][$source])) {
-    // Check for file upload errors and return FALSE if a
-    // lower level system error occurred.
+    // Check for file upload errors and return FALSE if a lower level system
+    // error occurred.
     switch ($_FILES['files']['error'][$source]) {
       // @see http://php.net/manual/en/features.file-upload.errors.php
       case UPLOAD_ERR_OK:
@@ -540,17 +670,17 @@ function file_save_upload($source, $vali
       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' => $source, '%maxsize' => format_size(file_upload_max_size()))), 'error');
-        return 0;
+        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' => $source)), 'error');
-        return 0;
+        return FALSE;
 
         // Unknown error
       default:
         drupal_set_message(t('The file %file could not be saved. An unknown error has occurred.', array('%file' => $source)), 'error');
-        return 0;
+        return FALSE;
     }
 
     // Build the list of non-munged extensions.
@@ -563,9 +693,12 @@ function file_save_upload($source, $vali
 
     // Begin building file object.
     $file = new stdClass();
+    $file->uid      = $user->uid;
+    $file->status   = FILE_STATUS_TEMPORARY;
     $file->filename = file_munge_filename(trim(basename($_FILES['files']['name'][$source]), '.'), $extensions);
     $file->filepath = $_FILES['files']['tmp_name'][$source];
     $file->filemime = $_FILES['files']['type'][$source];
+    $file->filesize = $_FILES['files']['size'][$source];
 
     // Rename potentially executable files, to help prevent exploits.
     if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) {
@@ -576,54 +709,53 @@ function file_save_upload($source, $vali
 
     // If the destination is not provided, or is not writable, then use the
     // temporary directory.
-    if (empty($dest) || file_check_path($dest) === FALSE) {
-      $dest = file_directory_temp();
+    if (empty($destination) || file_check_path($destination) === FALSE) {
+      $destination = file_directory_temp();
     }
 
     $file->source = $source;
-    $file->destination = file_destination(file_create_path($dest . '/' . $file->filename), $replace);
-    $file->filesize = $_FILES['files']['size'][$source];
+    $file->destination = file_destination(file_create_path($destination . '/' . $file->filename), $replace);
 
-    // Call the validation functions.
+    // Call the validation functions specified by this function's caller.
     $errors = array();
     foreach ($validators as $function => $args) {
       array_unshift($args, $file);
       $errors = array_merge($errors, call_user_func_array($function, $args));
     }
 
-    // Check for validation errors.
+    // Let other modules perform validation on the new file.
+    $errors = array_merge($errors, module_invoke_all('file_validate', $file));
+ 
+    // Check for errors. 
     if (!empty($errors)) {
       $message = t('The selected file %name could not be uploaded.', array('%name' => $file->filename));
       if (count($errors) > 1) {
-        $message .= '
- ' . implode('
- ', $errors) . '
';
+        $message .= theme('item_list', $errors);
       }
       else {
         $message .= ' ' . array_pop($errors);
       }
       form_set_error($source, $message);
-      return 0;
+      return FALSE;
     }
 
-    // Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary directory.
-    // This overcomes open_basedir restrictions for future file operations.
+    // Move uploaded files from PHP's upload_tmp_dir to Drupal's temporary 
+    // directory. This overcomes open_basedir restrictions for future file
+    // operations.
     $file->filepath = $file->destination;
     if (!move_uploaded_file($_FILES['files']['tmp_name'][$source], $file->filepath)) {
       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->filepath));
-      return 0;
+      return FALSE;
     }
 
-    // If we made it this far it's safe to record this file in the database.
-    $file->uid = $user->uid;
-    $file->status = FILE_STATUS_TEMPORARY;
-    $file->timestamp = time();
-    drupal_write_record('files', $file);
-
-    // Add file to the cache.
-    $upload_cache[$source] = $file;
-    return $file;
+    if ($file = file_save($file)) {
+      // Add file to the cache.
+      $upload_cache[$source] = $file;
+      return $file;
+    }
   }
-  return 0;
+  return FALSE;
 }
 
 /**
@@ -652,7 +784,8 @@ function file_validate_name_length($file
  * @param $extensions
  *   A string with a space separated
  * @return
- *   An array. If the file extension is not allowed, it will contain an error message.
+ *   An array. If the file extension is not allowed, it will contain an error
+ *   message.
  */
 function file_validate_extensions($file, $extensions) {
   global $user;
@@ -679,10 +812,11 @@ function file_validate_extensions($file,
  *   An integer specifying the maximum file size in bytes. Zero indicates that
  *   no limit should be enforced.
  * @param $$user_limit
- *   An integer specifying the maximum number of bytes the user is allowed. Zero
- *   indicates that no limit should be enforced.
+ *   An integer specifying the maximum number of bytes the user is allowed.
+ *   Zero indicates that no limit should be enforced.
  * @return
- *   An array. If the file size exceeds limits, it will contain an error message.
+ *   An array. If the file size exceeds limits, it will contain an error
+ *   message.
  */
 function file_validate_size($file, $file_limit = 0, $user_limit = 0) {
   global $user;
@@ -727,15 +861,16 @@ function file_validate_is_image(&$file) 
  * maximum and minimum dimensions. Non-image files will be ignored.
  *
  * @param $file
- *   A Drupal file object. This function may resize the file affecting its size.
+ *   A Drupal file object. This function may resize the file affecting its
+ *   size.
  * @param $maximum_dimensions
  *   An optional string in the form WIDTHxHEIGHT e.g. '640x480' or '85x85'. If
  *   an image toolkit is installed the image will be resized down to these
  *   dimensions. A value of 0 indicates no restriction on size, so resizing
  *   will be attempted.
  * @param $minimum_dimensions
- *   An optional string in the form WIDTHxHEIGHT. This will check that the image
- *   meets a minimum size. A value of 0 indicates no restriction.
+ *   An optional string in the form WIDTHxHEIGHT. This will check that the
+ *   image meets a minimum size. A value of 0 indicates no restriction.
  * @return
  *   An array. If the file is an image and did not meet the requirements, it
  *   will contain an error message.
@@ -777,47 +912,94 @@ function file_validate_image_resolution(
 }
 
 /**
- * Save a string to the specified destination.
+ * Save a string to the specified destination and create a database file entry.
  *
- * @param $data A string containing the contents of the file.
- * @param $dest A string containing the destination location.
- * @param $replace Replace behavior when the destination file already exists.
- *   - FILE_EXISTS_REPLACE - Replace the existing file
- *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is unique
+ * @param $data 
+ *   A string containing the contents of the file.
+ * @param $destination 
+ *   A string containing the destination location.
+ * @param $replace 
+ *   Replace behavior when the destination file already exists:
+ *   - FILE_EXISTS_REPLACE - Replace the existing file.
+ *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
+ *                          unique.
  *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
- *
- * @return A string containing the resulting filename or 0 on error
+ * @return 
+ *   A string containing the resulting filename or FALSE on error
  */
-function file_save_data($data, $dest, $replace = FILE_EXISTS_RENAME) {
-  $temp = file_directory_temp();
-  // On Windows, tempnam() requires an absolute path, so we use realpath().
-  $file = tempnam(realpath($temp), 'file');
-  if (!$fp = fopen($file, 'wb')) {
-    drupal_set_message(t('The file could not be created.'), 'error');
-    return 0;
+function file_save_data($data, $destination, $replace = FILE_EXISTS_RENAME) {
+  global $user;
+
+  if ($filepath = file_save_data_plain($data, $destination, $replace)) {
+    // Create a file object.
+    $file = new stdClass();
+    $file->filepath = $filepath;
+    $file->filename = basename($file->filepath);
+    $file->filemime = 'text/plain';
+    $file->uid      = $user->uid;
+    $file->status   = FILE_STATUS_PERMANENT;
+    return file_save($file);
   }
-  fwrite($fp, $data);
-  fclose($fp);
+  return FALSE;
+}
 
-  if (!file_move($file, $dest, $replace)) {
-    return 0;
+/**
+ * Save a string to the specified destination.
+ *
+ * This function is identical to file_save_data() except the file will not be
+ * saved to the files table.
+ *
+ * @param $data
+ *   A string containing the contents of the file.
+ * @param $destination
+ *   A string containing the destination location.
+ * @param $replace 
+ *   Replace behavior when the destination file already exists:
+ *   - FILE_EXISTS_REPLACE - Replace the existing file.
+ *   - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is
+ *                          unique.
+ *   - FILE_EXISTS_ERROR - Do nothing and return FALSE.
+ * @return
+ *   A string with the path of the resulting file, or FALSE on error.
+ */
+function file_save_data_plain($data, $destination, $replace = FILE_EXISTS_RENAME) {
+  global $user;
+
+  // TODO: we should get the new name and then call file_put_contents() on the
+  // renamed filename.
+
+  // Write the data to a temporary file.
+  $temp_name = tempnam(file_directory_temp(), 'file');
+
+  if (file_put_contents($temp_name, $data) === FALSE) {
+    drupal_set_message(t('The file could not be created.'), 'error');
+    return FALSE;
   }
 
-  return $file;
+  // Move the file to its final destination.
+  return file_move_plain($temp_name, $destination, $replace);
 }
 
 /**
  * Set the status of a file.
  *
- * @param file A Drupal file object
- * @param status A status value to set the file to.
- * @return FALSE on failure, TRUE on success and $file->status will contain the
- *     status.
+ * @param $file 
+ *   A Drupal file object.
+ * @param $status 
+ *   A status value to set the file to.
+ *   - FILE_STATUS_TEMPORARY - A temporary file that Drupal's garbage
+ *                             collection will remove.
+ *   - FILE_STATUS_PERMANENT - A permanent file that Drupal's garbage
+ *                             collection will not remove.
+ * @return
+ *   File object if the change is successful, or FALSE in the event of an
+ *   error.
  */
-function file_set_status(&$file, $status) {
+function file_set_status($file, $status =  FILE_STATUS_PERMANENT) {
   if (db_query('UPDATE {files} SET status = %d WHERE fid = %d', $status, $file->fid)) {
     $file->status = $status;
-    return TRUE;
+    module_invoke_all('file_status', $file);
+    return $file;
   }
   return FALSE;
 }
@@ -826,8 +1008,10 @@ function file_set_status(&$file, $status
  * Transfer file using http to client. Pipes a file through Drupal to the
  * client.
  *
- * @param $source File to transfer.
- * @param $headers An array of http headers to send along with file.
+ * @param $source
+ *   String specifying the file path to transfer.
+ * @param $headers
+ *   An array of http headers to send along with file.
  */
 function file_transfer($source, $headers) {
   ob_end_clean();
@@ -910,7 +1094,8 @@ function file_download() {
  * @param $min_depth
  *   Minimum depth of directories to return files from.
  * @param $depth
- *   Current depth of recursion. This parameter is only used internally and should not be passed.
+ *   Current depth of recursion. This parameter is only used internally and
+ *   should not be passed.
  *
  * @return
  *   An associative array (keyed on the provided key) of objects with
@@ -929,7 +1114,8 @@ function file_scan_directory($dir, $mask
           $files = array_merge(file_scan_directory("$dir/$file", $mask, $nomask, $callback, $recurse, $key, $min_depth, $depth + 1), $files);
         }
         elseif ($depth >= $min_depth && ereg($mask, $file)) {
-          // Always use this match over anything already set in $files with the same $$key.
+          // Always use this match over anything already set in $files with the
+          // same $$key.
           $filename = "$dir/$file";
           $basename = basename($file);
           $name = substr($basename, 0, strrpos($basename, '.'));
@@ -983,7 +1169,8 @@ function file_directory_temp() {
       }
     }
 
-    // if a directory has been found, use it, otherwise default to 'files/tmp' or 'files\\tmp';
+    // if a directory has been found, use it, otherwise default to 'files/tmp'
+    // or 'files\\tmp';
     $temporary_directory = $temporary_directory ? $temporary_directory : file_directory_path() . $path_delimiter . 'tmp';
     variable_set('file_directory_temp', $temporary_directory);
   }
@@ -1004,7 +1191,8 @@ function file_directory_path() {
  * Determine the maximum file upload size by querying the PHP settings.
  *
  * @return
- *   A file size limit in bytes based on the PHP upload_max_filesize and post_max_size
+ *   A file size limit in bytes based on the PHP upload_max_filesize and
+ *   post_max_size
  */
 function file_upload_max_size() {
   static $max_size = -1;
@@ -1018,5 +1206,64 @@ function file_upload_max_size() {
 }
 
 /**
+ * Load a file object from the database.
+ *
+ * @param $file_id
+ *   A numeric file id or string containing the file path.
+ * @param $reset
+ *   Whether to reset the internal file_load cache.
+ */
+function file_load($file_id, $reset = NULL) {
+  static $files = array();
+
+  if ($reset) {
+    $files = array();
+  }
+
+  if (is_numeric($file_id)) {
+    if (isset($files[$file_id])) {
+      return clone $files[$file_id];
+    }
+    $file = db_fetch_object(db_query('SELECT f.* FROM {files} f WHERE f.fid = %d', $file_id));
+  }
+  else {
+    $file = db_fetch_object(db_query("SELECT f.* FROM {files} f WHERE f.filepath = '%s'", $file_id));
+  }
+
+  module_invoke_all('file_load', $file);
+
+  // Cache the fully loaded value.
+  $files[$file->fid] = clone $file;
+  return $file;
+}
+
+/**
+ * Save a file object to the database.
+ *
+ * If the $file->fid is not set a new record will be added. Re-saving an
+ * existing file will not change its status.
+ *
+ * @param $file
+ *   A file object returned by file_load().
+ * @return
+ *   The updated file object.
+ */
+function file_save($file) {
+  $file->timestamp = time();
+  $file->filesize = filesize($file->filepath);
+  
+  if (empty($file->fid)) {
+    drupal_write_record('files', $file);
+    module_invoke_all('file_insert', $file);
+  }
+  else {
+    drupal_write_record('files', $file, 'fid');
+    module_invoke_all('file_update', $file);
+  }
+    
+  return $file;
+}
+
+/**
  * @} End of "defgroup file".
  */
Index: modules/blogapi/blogapi.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/blogapi/blogapi.module,v
retrieving revision 1.119
diff -u -p -r1.119 blogapi.module
--- modules/blogapi/blogapi.module	13 May 2008 18:13:43 -0000	1.119
+++ modules/blogapi/blogapi.module	30 May 2008 20:44:18 -0000
@@ -379,12 +379,12 @@ function blogapi_metaweblog_new_media_ob
     return blogapi_error(t('No file sent.'));
   }
 
-  if (!$file = file_save_data($data, $name)) {
+  if (!$filepath = file_save_data_plain($data, $name)) {
     return blogapi_error(t('Error storing file.'));
   }
 
   // Return the successful result.
-  return array('url' => file_create_url($file), 'struct');
+  return array('url' => file_create_url($filepath), 'struct');
 }
 /**
  * Blogging API callback. Returns a list of the taxonomy terms that can be
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.76
diff -u -p -r1.76 system.admin.inc
--- modules/system/system.admin.inc	10 May 2008 07:32:02 -0000	1.76
+++ modules/system/system.admin.inc	30 May 2008 20:44:19 -0000
@@ -338,9 +338,9 @@ function system_theme_settings(&$form_st
     // The image was saved using file_save_upload() and was added to the
     // files table as a temporary file. We'll make a copy and let the garbage
     // collector delete the original upload.
-    if (file_copy($file, $filename, FILE_EXISTS_REPLACE)) {
+    if ($filepath = file_copy_plain($file->filepath, $filename, FILE_EXISTS_REPLACE)) {
       $_POST['default_logo'] = 0;
-      $_POST['logo_path'] = $file->filepath;
+      $_POST['logo_path'] = $filepath;
       $_POST['toggle_logo'] = 1;
     }
   }
@@ -353,9 +353,9 @@ function system_theme_settings(&$form_st
     // The image was saved using file_save_upload() and was added to the
     // files table as a temporary file. We'll make a copy and let the garbage
     // collector delete the original upload.
-    if (file_copy($file, $filename)) {
+    if ($filepath = file_copy_plain($file->filepath, $filename, FILE_EXISTS_REPLACE)) {
       $_POST['default_favicon'] = 0;
-      $_POST['favicon_path'] = $file->filepath;
+      $_POST['favicon_path'] = $filepath;
       $_POST['toggle_favicon'] = 1;
     }
   }
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.602
diff -u -p -r1.602 system.module
--- modules/system/system.module	7 May 2008 19:17:50 -0000	1.602
+++ modules/system/system.module	30 May 2008 20:44:19 -0000
@@ -1382,12 +1382,14 @@ function system_cron() {
     if (file_exists($file->filepath)) {
       // If files that exist cannot be deleted, continue so the database remains
       // consistent.
-      if (!file_delete($file->filepath)) {
-        watchdog('file system', 'Could not delete temporary file "%path" during garbage collection', array('%path' => $file->filepath), 'error');
+      if (!file_delete($file)) {
+        watchdog('file system', t('Could not delete temporary file "%path" during garbage collection', array('%path' => $file->filepath)), 'error');
         continue;
       }
     }
-    db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
+    else {
+      db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
+    }
   }
 }
 
Index: modules/upload/upload.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload/upload.admin.inc,v
retrieving revision 1.9
diff -u -p -r1.9 upload.admin.inc
--- modules/upload/upload.admin.inc	20 Apr 2008 07:58:38 -0000	1.9
+++ modules/upload/upload.admin.inc	30 May 2008 20:44:19 -0000
@@ -74,11 +74,10 @@ function upload_admin_settings() {
     '#field_suffix' => '' . t('WIDTHxHEIGHT') . ''
   );
   $form['settings_general']['upload_list_default'] = array(
-    '#type' => 'select',
+    '#type' => 'checkbox',
     '#title' => t('List files by default'),
     '#default_value' => variable_get('upload_list_default', 1),
-    '#options' => array(0 => t('No'), 1 => t('Yes')),
-    '#description' => t('Display attached files when viewing a post.'),
+    '#description' => t('Determines whether attached files are shown to users by default.'),
   );
 
   $form['settings_general']['upload_extensions_default'] = array(
Index: modules/upload/upload.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload/upload.module,v
retrieving revision 1.202
diff -u -p -r1.202 upload.module
--- modules/upload/upload.module	14 May 2008 13:19:48 -0000	1.202
+++ modules/upload/upload.module	30 May 2008 20:44:19 -0000
@@ -147,12 +147,12 @@ function _upload_file_limits($user) {
  * Implementation of hook_file_download().
  */
 function upload_file_download($filepath) {
-  $filepath = file_create_path($filepath);
-  $result = db_query("SELECT f.* FROM {files} f INNER JOIN {upload} u ON f.fid = u.fid WHERE filepath = '%s'", $file);
+  if (!user_access('view uploaded files')) {
+    return -1;
+  }
+  $filepath = file_create_path($file);
+  $result = db_query("SELECT f.* FROM {files} f INNER JOIN {upload} u ON f.fid = u.fid WHERE filepath = '%s'", $filepath);
   if ($file = db_fetch_object($result)) {
-    if (!user_access('view uploaded files')) {
-      return -1;
-    }
     return array(
       'Content-Type: ' . $file->filemime,
       'Content-Length: ' . $file->filesize,
@@ -263,6 +263,38 @@ function upload_form_alter(&$form, $form
 }
 
 /**
+ * Implementation of hook_file_load().
+ */
+function upload_file_load(&$file, $source = NULL) {
+  // Add the upload specific data into the file object. 
+  $values = db_fetch_array(db_query('SELECT * FROM {upload} u WHERE u.fid = %d', $file->fid));
+  foreach ((array)$values as $key => $value) {
+    $file->{$key} = $value;
+  }
+}
+
+/**
+ * Implementation of hook_file_references().
+ */
+function upload_file_references(&$file, $source = NULL) {
+  // If upload.module is still using a file, do not let other modules delete it.
+  $count = db_result(db_query('SELECT count(*) FROM {upload} WHERE fid = %d', $file->fid));
+  if ($count) {
+    // return the name of the module and how many references it has to the file.
+    return array('upload' => $count);
+  }
+}
+ 
+/**
+ * Implementation of hook_file_delete().
+ */
+function upload_file_delete(&$file, $source = NULL) {
+  // Delete all information associated with the file.
+  db_query('DELETE FROM {upload} WHERE fid = %d', $file->fid);
+}
+
+
+/**
  * Implementation of hook_nodeapi().
  */
 function upload_nodeapi(&$node, $op, $teaser) {
@@ -406,13 +438,15 @@ function upload_save(&$node) {
       // If the file isn't used by any other revisions delete it.
       $count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $fid));
       if ($count < 1) {
-        file_delete($file->filepath);
+        file_delete($file);
         db_query('DELETE FROM {files} WHERE fid = %d', $fid);
       }
 
       // Remove it from the session in the case of new uploads,
       // that you want to disassociate before node submission.
       unset($_SESSION['upload_files'][$fid]);
+      // Try to clean up a file that is no longer in use.
+      file_delete($file);
       // Move on, so the removed file won't be added to new revisions.
       continue;
     }
@@ -420,13 +454,12 @@ function upload_save(&$node) {
     // Create a new revision, or associate a new file needed.
     if (!empty($node->old_vid) || isset($_SESSION['upload_files'][$fid])) {
       db_query("INSERT INTO {upload} (fid, nid, vid, list, description, weight) VALUES (%d, %d, %d, %d, '%s', %d)", $file->fid, $node->nid, $node->vid, $file->list, $file->description, $file->weight);
-      file_set_status($file, FILE_STATUS_PERMANENT);
     }
     // Update existing revision.
     else {
       db_query("UPDATE {upload} SET list = %d, description = '%s', weight = %d WHERE fid = %d AND vid = %d", $file->list, $file->description, $file->weight, $file->fid, $node->vid);
-      file_set_status($file, FILE_STATUS_PERMANENT);
     }
+    file_set_status($file, FILE_STATUS_PERMANENT);
   }
   // Empty the session storage after save. We use this variable to track files
   // that haven't been related to the node yet.
@@ -434,38 +467,23 @@ function upload_save(&$node) {
 }
 
 function upload_delete($node) {
-  $files = array();
-  $result = db_query('SELECT DISTINCT f.* FROM {upload} u INNER JOIN {files} f ON u.fid = f.fid WHERE u.nid = %d', $node->nid);
-  while ($file = db_fetch_object($result)) {
-    $files[$file->fid] = $file;
+  db_query('DELETE FROM {upload} WHERE nid = %d', $node->nid);
+  if (!is_array($node->files)) {
+    return; 
   }
-
-  foreach ($files as $fid => $file) {
-    // Delete all files associated with the node
-    db_query('DELETE FROM {files} WHERE fid = %d', $fid);
-    file_delete($file->filepath);
+  foreach($node->files as $file) {
+    file_delete($file);
   }
-
-  // Delete all file revision information associated with the node
-  db_query('DELETE FROM {upload} WHERE nid = %d', $node->nid);
 }
 
 function upload_delete_revision($node) {
-  if (is_array($node->files)) {
-    foreach ($node->files as $file) {
-      // Check if the file will be used after this revision is deleted
-      $count = db_result(db_query('SELECT COUNT(fid) FROM {upload} WHERE fid = %d', $file->fid));
-
-      // if the file won't be used, delete it
-      if ($count < 2) {
-        db_query('DELETE FROM {files} WHERE fid = %d', $file->fid);
-        file_delete($file->filepath);
-      }
-    }
-  }
-
-  // delete the revision
   db_query('DELETE FROM {upload} WHERE vid = %d', $node->vid);
+  if (!is_array($node->files)) {
+    return;
+  }
+  foreach ($node->files as $file) {
+    file_delete($file);
+  }
 }
 
 function _upload_form($node) {
@@ -479,11 +497,17 @@ function _upload_form($node) {
   if (!empty($node->files) && is_array($node->files)) {
     $form['files']['#theme'] = 'upload_form_current';
     $form['files']['#tree'] = TRUE;
-    foreach ($node->files as $key => $file) {
+    foreach ($node->files as $file) {
       $file = (object)$file;
-      $description = file_create_url($file->filepath);
-      $description = "" . check_plain($description) . "";
-      $form['files'][$key]['description'] = array('#type' => 'textfield', '#default_value' => !empty($file->description) ? $file->description : $file->filename, '#maxlength' => 256, '#description' => $description );
+      $key = $file->fid;
+
+      $form['files'][$key]['description'] = array(
+        '#type' => 'textfield',
+        '#default_value' => !empty($file->description) ? $file->description : $file->filename,
+        '#maxlength' => 256,
+        '#description' => '' . file_create_url($file->filepath) . '',
+      );
+
       $form['files'][$key]['size'] = array('#value' => format_size($file->filesize));
       $form['files'][$key]['remove'] = array('#type' => 'checkbox', '#default_value' => !empty($file->remove));
       $form['files'][$key]['list'] = array('#type' => 'checkbox',  '#default_value' => $file->list);
@@ -498,12 +522,26 @@ function _upload_form($node) {
 
   if (user_access('upload files')) {
     $limits = _upload_file_limits($user);
+
+    $limit_description = t('The maximum size of file uploads is %filesize. ', array('%filesize' => format_size($limits['file_size'])));
+    if (!empty($limits['resolution'])) {
+      if (image_get_toolkit()) {
+        $limit_description .= t('Images larger than %resolution will be resized. ', array('%resolution' => $limits['resolution']));
+      }
+      else {
+        $limit_description .= t('Images may not be larger than %resolution. ', array('%resolution' => $limits['resolution']));
+      }
+    }
+    if ($user->uid != 1) {
+      $limit_description .= t('Only files with the following extensions may be uploaded: %extensions. ', array('%extensions' => $limits['extensions']));
+    }
+
     $form['new']['#weight'] = 10;
     $form['new']['upload'] = array(
       '#type' => 'file',
       '#title' => t('Attach new file'),
       '#size' => 40,
-      '#description' => ($limits['resolution'] ? t('Images are larger than %resolution will be resized. ', array('%resolution' => $limits['resolution'])) : '') . t('The maximum upload size is %filesize. Only files with the following extensions may be uploaded: %extensions. ', array('%extensions' => $limits['extensions'], '%filesize' => format_size($limits['file_size']))),
+      '#description' => $limit_description,
     );
     $form['new']['attach'] = array(
       '#type' => 'submit',
@@ -565,9 +603,9 @@ function upload_load($node) {
   $files = array();
 
   if ($node->vid) {
-    $result = db_query('SELECT * FROM {files} f INNER JOIN {upload} r ON f.fid = r.fid WHERE r.vid = %d ORDER BY r.weight, f.fid', $node->vid);
+    $result = db_query('SELECT u.fid FROM {upload} u WHERE u.vid = %d ORDER BY u.fid', $node->vid);
     while ($file = db_fetch_object($result)) {
-      $files[$file->fid] = $file;
+      $files[$file->fid] = file_load($file->fid);
     }
   }
 
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.909
diff -u -p -r1.909 user.module
--- modules/user/user.module	26 May 2008 17:12:55 -0000	1.909
+++ modules/user/user.module	30 May 2008 20:44:19 -0000
@@ -395,8 +395,8 @@ function user_validate_picture(&$form, &
   );
   if ($file = file_save_upload('picture_upload', $validators)) {
     // Remove the old picture.
-    if (isset($form_state['values']['_account']->picture) && file_exists($form_state['values']['_account']->picture)) {
-      file_delete($form_state['values']['_account']->picture);
+    if (isset($form_state['values']['_account']->picture)) {
+      file_delete_plain($form_state['values']['_account']->picture);
     }
 
     // The image was saved using file_save_upload() and was added to the
@@ -404,8 +404,8 @@ function user_validate_picture(&$form, &
     // collector delete the original upload.
     $info = image_get_info($file->filepath);
     $destination = variable_get('user_picture_path', 'pictures') . '/picture-' . $form['#uid'] . '.' . $info['extension'];
-    if (file_copy($file, $destination, FILE_EXISTS_REPLACE)) {
-      $form_state['values']['picture'] = $file->filepath;
+    if (file_copy_plain($file->filepath, $destination, FILE_EXISTS_REPLACE)) {
+      $form_state['values']['picture'] = $destination;
     }
     else {
       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'))));
@@ -828,7 +828,7 @@ function template_preprocess_user_pictur
   $variables['picture'] = '';
   if (variable_get('user_pictures', 0)) {
     $account = $variables['account'];
-    if (!empty($account->picture) && file_exists($account->picture)) {
+    if (!empty($account->picture) && file_exists(file_create_path($account->picture))) {
       $picture = file_create_url($account->picture);
     }
     else if (variable_get('user_picture_default', '')) {
@@ -1521,8 +1521,8 @@ function _user_edit_submit($uid, &$edit)
   $user = user_load(array('uid' => $uid));
   // Delete picture if requested, and if no replacement picture was given.
   if (!empty($edit['picture_delete'])) {
-    if ($user->picture && file_exists($user->picture)) {
-      file_delete($user->picture);
+    if ($user->picture) {
+      file_delete_plain($user->picture);
     }
     $edit['picture'] = '';
   }