=== modified file 'modules/comment/comment.module'
--- modules/comment/comment.module	2009-09-22 07:36:57 +0000
+++ modules/comment/comment.module	2009-09-28 01:14:11 +0000
@@ -1236,135 +1236,144 @@ function comment_access($op, $comment) {
 function comment_save($comment) {
   global $user;
 
-  $defaults =  array(
-    'mail' => '',
-    'homepage' => '',
-    'name' => '',
-    'status' => user_access('post comments without approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED,
-  );
-  foreach ($defaults as $key => $default) {
-    if (!isset($comment->$key)) {
-      $comment->$key = $default;
-    }
-  }
-  // Make sure we have a bundle name.
-  if (!isset($comment->node_type)) {
-    $node = node_load($comment->nid);
-    $comment->node_type = 'comment_node_' . $node->type;
-  }
-
-  field_attach_presave('comment', $comment);
-
-  // Allow modules to alter the comment before saving.
-  module_invoke_all('comment_presave', $comment);
-
-  if ($comment->cid) {
-    // Update the comment in the database.
-    db_update('comment')
-      ->fields(array(
-        'status' => $comment->status,
-        'timestamp' => $comment->timestamp,
-        'subject' => $comment->subject,
-        'comment' => $comment->comment,
-        'format' => $comment->comment_format,
-        'uid' => $comment->uid,
-        'name' => $comment->name,
-        'mail' => $comment->mail,
-        'homepage' => $comment->homepage,
-      ))
-      ->condition('cid', $comment->cid)
-      ->execute();
-    field_attach_update('comment', $comment);
-    // Allow modules to respond to the updating of a comment.
-    module_invoke_all('comment_update', $comment);
-    // Add an entry to the watchdog log.
-    watchdog('content', 'Comment: updated %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)));
-  }
-  else {
-    // Add the comment to database. This next section builds the thread field.
-    // Also see the documentation for comment_build().
-    if ($comment->pid == 0) {
-      // This is a comment with no parent comment (depth 0): we start
-      // by retrieving the maximum thread level.
-      $max = db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid))->fetchField();
-      // Strip the "/" from the end of the thread.
-      $max = rtrim($max, '/');
-      // Finally, build the thread field for this new comment.
-      $thread = int2vancode(vancode2int($max) + 1) . '/';
-    }
-    else {
-      // This is a comment with a parent comment, so increase the part of the
-      // thread value at the proper depth.
-
-      // Get the parent comment:
-      $parent = comment_load($comment->pid);
-      // Strip the "/" from the end of the parent thread.
-      $parent->thread = (string) rtrim((string) $parent->thread, '/');
-      // Get the max value in *this* thread.
-      $max = db_query("SELECT MAX(thread) FROM {comment} WHERE thread LIKE :thread AND nid = :nid", array(
-        ':thread' => $parent->thread . '.%',
-        ':nid' => $comment->nid,
-      ))->fetchField();
-
-      if ($max == '') {
-        // First child of this parent.
-        $thread = $parent->thread . '.' . int2vancode(0) . '/';
-      }
-      else {
-        // Strip the "/" at the end of the thread.
-        $max = rtrim($max, '/');
-        // Get the value at the correct depth.
-        $parts = explode('.', $max);
-        $parent_depth = count(explode('.', $parent->thread));
-        $last = $parts[$parent_depth];
-        // Finally, build the thread field for this new comment.
-        $thread = $parent->thread . '.' . int2vancode(vancode2int($last) + 1) . '/';
-      }
-    }
-
-    if (empty($comment->timestamp)) {
-      $comment->timestamp = REQUEST_TIME;
-    }
-
-    if ($comment->uid === $user->uid && isset($user->name)) { // '===' Need to modify anonymous users as well.
-      $comment->name = $user->name;
-    }
-
-    $comment->cid = db_insert('comment')
-      ->fields(array(
-        'nid' => $comment->nid,
-        'pid' => empty($comment->pid) ? 0 : $comment->pid,
-        'uid' => $comment->uid,
-        'subject' => $comment->subject,
-        'comment' => $comment->comment,
-        'format' => $comment->comment_format,
-        'hostname' => ip_address(),
-        'timestamp' => $comment->timestamp,
-        'status' => $comment->status,
-        'thread' => $thread,
-        'name' => $comment->name,
-        'mail' => $comment->mail,
-        'homepage' => $comment->homepage,
-      ))
-      ->execute();
-
-    // Ignore slave server temporarily to give time for the
-    // saved node to be propagated to the slave.
-    db_ignore_slave();
-
-    field_attach_insert('comment', $comment);
-
-    // Tell the other modules a new comment has been submitted.
-    module_invoke_all('comment_insert', $comment);
-    // Add an entry to the watchdog log.
-    watchdog('content', 'Comment: added %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)));
-  }
-  _comment_update_node_statistics($comment->nid);
-  // Clear the cache so an anonymous user can see his comment being added.
-  cache_clear_all();
-
-  if ($comment->status == COMMENT_PUBLISHED) {
-    module_invoke_all('comment_publish', $comment);
+  // Wrap the entire comment save routine in a transaction for better
+  // data integrity on those databases that support transactions.
+  $transaction = db_transaction();
+  try {
+    $defaults =  array(
+	    'mail' => '',
+	    'homepage' => '',
+	    'name' => '',
+	    'status' => user_access('post comments without approval') ? COMMENT_PUBLISHED : COMMENT_NOT_PUBLISHED,
+	  );
+	  foreach ($defaults as $key => $default) {
+	    if (!isset($comment->$key)) {
+	      $comment->$key = $default;
+	    }
+	  }
+	  // Make sure we have a bundle name.
+	  if (!isset($comment->node_type)) {
+	    $node = node_load($comment->nid);
+	    $comment->node_type = 'comment_node_' . $node->type;
+	  }
+
+	  field_attach_presave('comment', $comment);
+
+	  // Allow modules to alter the comment before saving.
+	  module_invoke_all('comment_presave', $comment);
+
+	  if ($comment->cid) {
+	    // Update the comment in the database.
+	    db_update('comment')
+	      ->fields(array(
+	        'status' => $comment->status,
+	        'timestamp' => $comment->timestamp,
+	        'subject' => $comment->subject,
+	        'comment' => $comment->comment,
+	        'format' => $comment->comment_format,
+	        'uid' => $comment->uid,
+	        'name' => $comment->name,
+	        'mail' => $comment->mail,
+	        'homepage' => $comment->homepage,
+	      ))
+	      ->condition('cid', $comment->cid)
+	      ->execute();
+	    field_attach_update('comment', $comment);
+	    // Allow modules to respond to the updating of a comment.
+	    module_invoke_all('comment_update', $comment);
+	    // Add an entry to the watchdog log.
+	    watchdog('content', 'Comment: updated %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)));
+	  }
+	  else {
+	    // Add the comment to database. This next section builds the thread field.
+	    // Also see the documentation for comment_build().
+	    if ($comment->pid == 0) {
+	      // This is a comment with no parent comment (depth 0): we start
+	      // by retrieving the maximum thread level.
+	      $max = db_query('SELECT MAX(thread) FROM {comment} WHERE nid = :nid', array(':nid' => $comment->nid))->fetchField();
+	      // Strip the "/" from the end of the thread.
+	      $max = rtrim($max, '/');
+	      // Finally, build the thread field for this new comment.
+	      $thread = int2vancode(vancode2int($max) + 1) . '/';
+	    }
+	    else {
+	      // This is a comment with a parent comment, so increase the part of the
+	      // thread value at the proper depth.
+
+	      // Get the parent comment:
+	      $parent = comment_load($comment->pid);
+	      // Strip the "/" from the end of the parent thread.
+	      $parent->thread = (string) rtrim((string) $parent->thread, '/');
+	      // Get the max value in *this* thread.
+	      $max = db_query("SELECT MAX(thread) FROM {comment} WHERE thread LIKE :thread AND nid = :nid", array(
+	        ':thread' => $parent->thread . '.%',
+	        ':nid' => $comment->nid,
+	      ))->fetchField();
+
+	      if ($max == '') {
+	        // First child of this parent.
+	        $thread = $parent->thread . '.' . int2vancode(0) . '/';
+	      }
+	      else {
+	        // Strip the "/" at the end of the thread.
+	        $max = rtrim($max, '/');
+	        // Get the value at the correct depth.
+	        $parts = explode('.', $max);
+	        $parent_depth = count(explode('.', $parent->thread));
+	        $last = $parts[$parent_depth];
+	        // Finally, build the thread field for this new comment.
+	        $thread = $parent->thread . '.' . int2vancode(vancode2int($last) + 1) . '/';
+	      }
+	    }
+
+	    if (empty($comment->timestamp)) {
+	      $comment->timestamp = REQUEST_TIME;
+	    }
+
+	    if ($comment->uid === $user->uid && isset($user->name)) { // '===' Need to modify anonymous users as well.
+	      $comment->name = $user->name;
+	    }
+
+	    $comment->cid = db_insert('comment')
+	      ->fields(array(
+	        'nid' => $comment->nid,
+	        'pid' => empty($comment->pid) ? 0 : $comment->pid,
+	        'uid' => $comment->uid,
+	        'subject' => $comment->subject,
+	        'comment' => $comment->comment,
+	        'format' => $comment->comment_format,
+	        'hostname' => ip_address(),
+	        'timestamp' => $comment->timestamp,
+	        'status' => $comment->status,
+	        'thread' => $thread,
+	        'name' => $comment->name,
+	        'mail' => $comment->mail,
+	        'homepage' => $comment->homepage,
+	      ))
+	      ->execute();
+
+	    // Ignore slave server temporarily to give time for the
+	    // saved node to be propagated to the slave.
+	    db_ignore_slave();
+
+	    field_attach_insert('comment', $comment);
+
+	    // Tell the other modules a new comment has been submitted.
+	    module_invoke_all('comment_insert', $comment);
+	    // Add an entry to the watchdog log.
+	    watchdog('content', 'Comment: added %subject.', array('%subject' => $comment->subject), WATCHDOG_NOTICE, l(t('view'), 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)));
+	  }
+	  _comment_update_node_statistics($comment->nid);
+	  // Clear the cache so an anonymous user can see his comment being added.
+	  cache_clear_all();
+
+	  if ($comment->status == COMMENT_PUBLISHED) {
+	    module_invoke_all('comment_publish', $comment);
+	  }
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    watchdog('node', $e->getMessage(), array(), WATCHDOG_WARNING);
   }
 }
 
@@ -2100,12 +2109,12 @@ function template_preprocess_comment(&$v
   $variables['signature'] = $comment->signature;
   $variables['title']     = l($comment->subject, 'comment/' . $comment->cid, array('fragment' => "comment-$comment->cid"));
   $variables['template_files'][] = 'comment-' . $variables['node']->type;
-  
+
   // Helpful $content variable for templates.
   foreach (element_children($variables['elements']) as $key) {
     $variables['content'][$key] = $variables['elements'][$key];
   }
-  
+
   // Set status to a string representation of comment->status.
   if (isset($comment->in_preview)) {
     $variables['status']  = 'comment-preview';

=== modified file 'modules/node/node.module'
--- modules/node/node.module	2009-09-25 14:24:34 +0000
+++ modules/node/node.module	2009-09-28 00:56:54 +0000
@@ -851,97 +851,106 @@ function node_submit($node) {
  *   omitted (or $node->is_new is TRUE), a new node will be added.
  */
 function node_save($node) {
-  field_attach_presave('node', $node);
-  // Let modules modify the node before it is saved to the database.
-  module_invoke_all('node_presave', $node);
-  global $user;
-
-  if (!isset($node->is_new)) {
-    $node->is_new = empty($node->nid);
-  }
-
-  // Apply filters to some default node fields:
-  if ($node->is_new) {
-    // Insert a new node.
-    $node->is_new = TRUE;
-
-    // When inserting a node, $node->log must be set because
-    // {node_revision}.log does not (and cannot) have a default
-    // value. If the user does not have permission to create
-    // revisions, however, the form will not contain an element for
-    // log so $node->log will be unset at this point.
-    if (!isset($node->log)) {
-      $node->log = '';
-    }
-  }
-  elseif (!empty($node->revision)) {
-    $node->old_vid = $node->vid;
-    unset($node->vid);
-  }
-  else {
-    // When updating a node, avoid clobbering an existing log entry with an empty one.
-    if (empty($node->log)) {
-      unset($node->log);
-    }
-  }
-
-  // Set some required fields:
-  if (empty($node->created)) {
-    $node->created = REQUEST_TIME;
-  }
-  // The changed timestamp is always updated for bookkeeping purposes (revisions, searching, ...)
-  $node->changed = REQUEST_TIME;
-
-  $node->timestamp = REQUEST_TIME;
-  $update_node = TRUE;
-
-  // Generate the node table query and the node_revisions table query.
-  if ($node->is_new) {
-    drupal_write_record('node', $node);
-    _node_save_revision($node, $user->uid);
-    $op = 'insert';
-  }
-  else {
-    drupal_write_record('node', $node, 'nid');
-    if (!empty($node->revision)) {
-      _node_save_revision($node, $user->uid);
-    }
-    else {
-      _node_save_revision($node, $user->uid, 'vid');
-      $update_node = FALSE;
-    }
-    $op = 'update';
-  }
-  if ($update_node) {
-    db_update('node')
-      ->fields(array('vid' => $node->vid))
-      ->condition('nid', $node->nid)
-      ->execute();
-  }
-
-  // Call the node specific callback (if any). This can be
-  // node_invoke($node, 'insert') or
-  // node_invoke($node, 'update').
-  node_invoke($node, $op);
-
-  // Save fields.
-  $function = "field_attach_$op";
-  $function('node', $node);
-
-  module_invoke_all('node_' . $op, $node);
-
-  // Update the node access table for this node.
-  node_access_acquire_grants($node);
-
-  // Clear internal properties.
-  unset($node->is_new);
-
-  // Clear the page and block caches.
-  cache_clear_all();
-
-  // Ignore slave server temporarily to give time for the
-  // saved node to be propagated to the slave.
-  db_ignore_slave();
+	// Wrap the entire node save routine in a transaction for better
+	// data integrity on those databases that support transactions.
+  $transaction = db_transaction();
+	try {
+	  field_attach_presave('node', $node);
+	  // Let modules modify the node before it is saved to the database.
+	  module_invoke_all('node_presave', $node);
+	  global $user;
+
+	  if (!isset($node->is_new)) {
+	    $node->is_new = empty($node->nid);
+	  }
+
+	  // Apply filters to some default node fields:
+	  if ($node->is_new) {
+	    // Insert a new node.
+	    $node->is_new = TRUE;
+
+	    // When inserting a node, $node->log must be set because
+	    // {node_revision}.log does not (and cannot) have a default
+	    // value. If the user does not have permission to create
+	    // revisions, however, the form will not contain an element for
+	    // log so $node->log will be unset at this point.
+	    if (!isset($node->log)) {
+	      $node->log = '';
+	    }
+	  }
+	  elseif (!empty($node->revision)) {
+	    $node->old_vid = $node->vid;
+	    unset($node->vid);
+	  }
+	  else {
+	    // When updating a node, avoid clobbering an existing log entry with an empty one.
+	    if (empty($node->log)) {
+	      unset($node->log);
+	    }
+	  }
+
+	  // Set some required fields:
+	  if (empty($node->created)) {
+	    $node->created = REQUEST_TIME;
+	  }
+	  // The changed timestamp is always updated for bookkeeping purposes (revisions, searching, ...)
+	  $node->changed = REQUEST_TIME;
+
+	  $node->timestamp = REQUEST_TIME;
+	  $update_node = TRUE;
+
+	  // Generate the node table query and the node_revisions table query.
+	  if ($node->is_new) {
+	    drupal_write_record('node', $node);
+	    _node_save_revision($node, $user->uid);
+	    $op = 'insert';
+	  }
+	  else {
+	    drupal_write_record('node', $node, 'nid');
+	    if (!empty($node->revision)) {
+	      _node_save_revision($node, $user->uid);
+	    }
+	    else {
+	      _node_save_revision($node, $user->uid, 'vid');
+	      $update_node = FALSE;
+	    }
+	    $op = 'update';
+	  }
+	  if ($update_node) {
+	    db_update('node')
+	      ->fields(array('vid' => $node->vid))
+	      ->condition('nid', $node->nid)
+	      ->execute();
+	  }
+
+	  // Call the node specific callback (if any). This can be
+	  // node_invoke($node, 'insert') or
+	  // node_invoke($node, 'update').
+	  node_invoke($node, $op);
+
+	  // Save fields.
+	  $function = "field_attach_$op";
+	  $function('node', $node);
+
+	  module_invoke_all('node_' . $op, $node);
+
+	  // Update the node access table for this node.
+	  node_access_acquire_grants($node);
+
+	  // Clear internal properties.
+	  unset($node->is_new);
+
+	  // Clear the page and block caches.
+	  cache_clear_all();
+
+	  // Ignore slave server temporarily to give time for the
+	  // saved node to be propagated to the slave.
+	  db_ignore_slave();
+	}
+	catch (Exception $e) {
+	  $transaction->rollback();
+	  watchdog('node', $e->getMessage(), array(), WATCHDOG_WARNING);
+	}
 }
 
 /**
@@ -1056,7 +1065,7 @@ function node_build($node, $build_mode =
   $build = $node->content;
   // We don't need duplicate rendering info in node->content.
   unset($node->content);
-  
+
   $build += array(
     '#theme' => 'node',
     '#node' => $node,
@@ -1182,7 +1191,7 @@ function template_preprocess_node(&$vari
 
   // Flatten the node object's member fields.
   $variables = array_merge((array)$node, $variables);
-  
+
   // Helpful $content variable for templates.
   foreach (element_children($variables['elements']) as $key) {
     $variables['content'][$key] = $variables['elements'][$key];
@@ -1352,7 +1361,7 @@ function node_search_admin() {
   $form['content_ranking']['info'] = array(
     '#value' => '<em>' . t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') . '</em>'
   );
-  
+
   // Note: reversed to reflect that higher number = higher ranking.
   $options = drupal_map_assoc(range(0, 10));
   foreach (module_invoke_all('ranking') as $var => $values) {
@@ -1377,7 +1386,7 @@ function node_search_execute($keys = NUL
     ->condition('n.status', 1)
     ->addTag('node_access')
     ->searchExpression($keys, 'node');
-  
+
   // Insert special keywords.
   $query->setOption('type', 'n.type');
   $query->setOption('language', 'n.language');
@@ -1388,10 +1397,10 @@ function node_search_execute($keys = NUL
   if (!$query->executeFirstPass()) {
     return array();
   }
-  
+
   // Add the ranking expressions.
   _node_rankings($query);
-  
+
   // Add a count query.
   $inner_query = clone $query;
   $count_query = db_select($inner_query->fields('i', array('sid')));
@@ -1400,7 +1409,7 @@ function node_search_execute($keys = NUL
   $find = $query
     ->limit(10)
     ->execute();
-  
+
   // Load results.
   $results = array();
   foreach ($find as $item) {
@@ -1408,14 +1417,14 @@ function node_search_execute($keys = NUL
     $node = node_load($item->sid);
     node_build_content($node, 'search_result');
     $node->rendered = drupal_render($node->content);
-  
+
     // Fetch comments for snippet.
     $node->rendered .= ' ' . module_invoke('comment', 'node_update_index', $node);
     // Fetch terms for snippet.
     $node->rendered .= ' ' . module_invoke('taxonomy', 'node_update_index', $node);
-  
+
     $extra = module_invoke_all('node_search_result', $node);
-  
+
     $results[] = array(
       'link' => url('node/' . $item->sid, array('absolute' => TRUE)),
       'type' => check_plain(node_type_get_name($node)),

=== modified file 'modules/user/user.module'
--- modules/user/user.module	2009-09-25 15:14:18 +0000
+++ modules/user/user.module	2009-09-28 01:10:18 +0000
@@ -308,217 +308,229 @@ function user_load_by_name($name) {
  *   A fully-loaded $user object upon successful save or FALSE if the save failed.
  */
 function user_save($account, $edit = array(), $category = 'account') {
-  $table = drupal_get_schema('users');
-  $user_fields = $table['fields'];
-
-  if (!empty($edit['pass'])) {
-    // Allow alternate password hashing schemes.
-    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
-    $edit['pass'] = user_hash_password(trim($edit['pass']));
-    // Abort if the hashing failed and returned FALSE.
-    if (!$edit['pass']) {
-      return FALSE;
-    }
-  }
-  else {
-    // Avoid overwriting an existing password with a blank password.
-    unset($edit['pass']);
+  // Wrap the entire user save routine in a transaction for better
+  // data integrity on those databases that support transactions.
+  $transaction = db_transaction();
+  try {
+
+	  $table = drupal_get_schema('users');
+	  $user_fields = $table['fields'];
+
+	  if (!empty($edit['pass'])) {
+	    // Allow alternate password hashing schemes.
+	    require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
+	    $edit['pass'] = user_hash_password(trim($edit['pass']));
+	    // Abort if the hashing failed and returned FALSE.
+	    if (!$edit['pass']) {
+	      return FALSE;
+	    }
+	  }
+	  else {
+	    // Avoid overwriting an existing password with a blank password.
+	    unset($edit['pass']);
+	  }
+
+	  // Get the fields form so we can recognize the fields in the $edit
+	  // form that should not go into the serialized data array.
+	  $field_form = array();
+	  $field_form_state = array();
+	  $edit = (object) $edit;
+	  field_attach_form('user', $edit, $field_form, $field_form_state);
+
+	  // Presave fields.
+	  field_attach_presave('user', $edit);
+
+	  $edit = (array) $edit;
+
+	  if (!isset($account->is_new)) {
+	    $account->is_new = empty($account->uid);
+	  }
+	  if (is_object($account) && !$account->is_new) {
+	    user_module_invoke('update', $edit, $account, $category);
+	    $data = unserialize(db_query('SELECT data FROM {users} WHERE uid = :uid', array(':uid' => $account->uid))->fetchField());
+	    // Consider users edited by an administrator as logged in, if they haven't
+	    // already, so anonymous users can view the profile (if allowed).
+	    if (empty($edit['access']) && empty($account->access) && user_access('administer users')) {
+	      $edit['access'] = REQUEST_TIME;
+	    }
+	    foreach ($edit as $key => $value) {
+	      // Form fields that don't pertain to the users, user_roles, or
+	      // Field API are automatically serialized into the users.data
+	      // column.
+	      if (!in_array($key, array('roles', 'is_new')) && empty($user_fields[$key]) && empty($field_form[$key])) {
+	        if ($value === NULL) {
+	          unset($data[$key]);
+	        }
+	        else {
+	          $data[$key] = $value;
+	        }
+	      }
+	    }
+
+	    // Process picture uploads.
+	    if (!empty($edit['picture']->fid)) {
+	      $picture = $edit['picture'];
+	      // If the picture is a temporary file move it to its final location and
+	      // make it permanent.
+	      if (($picture->status & FILE_STATUS_PERMANENT) == 0) {
+	        $info = image_get_info($picture->uri);
+	        $picture_directory =  variable_get('file_default_scheme', 'public') . '://' . variable_get('user_picture_path', 'pictures');
+
+	        // Prepare the pictures directory.
+	        file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY);
+	        $destination = file_stream_wrapper_uri_normalize($picture_directory . '/picture-' . $account->uid . '.' . $info['extension']);
+
+	        if ($picture = file_move($picture, $destination, FILE_EXISTS_REPLACE)) {
+	          $picture->status |= FILE_STATUS_PERMANENT;
+	          $edit['picture'] = file_save($picture);
+	        }
+	      }
+	    }
+	    $edit['picture'] = empty($edit['picture']->fid) ? 0 : $edit['picture']->fid;
+
+	    $edit['data'] = $data;
+	    // Do not allow 'uid' to be changed.
+	    $edit['uid'] = $account->uid;
+	    // Save changes to the user table.
+	    $success = drupal_write_record('users', $edit, 'uid');
+	    if (!$success) {
+	      // The query failed - better to abort the save than risk further
+	      // data loss.
+
+	      // TODO: Fields change: I think this is a bug.  If no columns in
+	      // the user table are changed, drupal_write_record returns
+	      // FALSE because rowCount() (rows changed) is 0.  However,
+	      // non-users data may have been changed, e.g. fields.
+	      // return FALSE;
+	    }
+
+	    // If the picture changed or was unset, remove the old one. This step needs
+	    // to occur after updating the {users} record so that user_file_references()
+	    // doesn't report it in use and block the deletion.
+	    if (!empty($account->picture->fid) && ($edit['picture'] != $account->picture->fid)) {
+	      file_delete($account->picture);
+	    }
+
+	    // Reload user roles if provided.
+	    if (isset($edit['roles']) && is_array($edit['roles'])) {
+	      db_delete('users_roles')
+	        ->condition('uid', $account->uid)
+	        ->execute();
+
+	      $query = db_insert('users_roles')->fields(array('uid', 'rid'));
+	      foreach (array_keys($edit['roles']) as $rid) {
+	        if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
+	          $query->values(array(
+	            'uid' => $account->uid,
+	            'rid' => $rid,
+	          ));
+	        }
+	      }
+	      $query->execute();
+	    }
+
+	    // Delete a blocked user's sessions to kick them if they are online.
+	    if (isset($edit['status']) && $edit['status'] == 0) {
+	      drupal_session_destroy_uid($account->uid);
+	    }
+
+	    // If the password changed, delete all open sessions and recreate
+	    // the current one.
+	    if (!empty($edit['pass'])) {
+	      drupal_session_destroy_uid($account->uid);
+	      if ($account->uid == $GLOBALS['user']->uid) {
+	        drupal_session_regenerate();
+	      }
+	    }
+
+	    // Save Field data.
+	    $object = (object) $edit;
+	    field_attach_update('user', $object);
+
+	    // Refresh user object.
+	    $user = user_load($account->uid, TRUE);
+
+	    // Send emails after we have the new user object.
+	    if (isset($edit['status']) && $edit['status'] != $account->status) {
+	      // The user's status is changing; conditionally send notification email.
+	      $op = $edit['status'] == 1 ? 'status_activated' : 'status_blocked';
+	      _user_mail_notify($op, $user);
+	    }
+
+	    user_module_invoke('after_update', $edit, $user, $category);
+	  }
+	  else {
+	    // Allow 'created' to be set by the caller.
+	    if (!isset($edit['created'])) {
+	      $edit['created'] = REQUEST_TIME;
+	    }
+	    // Consider users created by an administrator as already logged in, so
+	    // anonymous users can view the profile (if allowed).
+	    if (empty($edit['access']) && user_access('administer users')) {
+	      $edit['access'] = REQUEST_TIME;
+	    }
+
+	    $edit['mail'] = trim($edit['mail']);
+	    $success = drupal_write_record('users', $edit);
+	    if (!$success) {
+	      // On a failed INSERT some other existing user's uid may be returned.
+	      // We must abort to avoid overwriting their account.
+	      return FALSE;
+	    }
+
+	    // Build the initial user object.
+	    $user = user_load($edit['uid'], TRUE);
+
+	    $object = (object) $edit;
+	    field_attach_insert('user', $object);
+
+	    user_module_invoke('insert', $edit, $user, $category);
+
+	    // Note, we wait with saving the data column to prevent module-handled
+	    // fields from being saved there.
+	    $data = array();
+	    foreach ($edit as $key => $value) {
+	      // Form fields that don't pertain to the users, user_roles, or
+	      // Field API are automatically serialized into the user.data
+	      // column.
+	      if ((!in_array($key, array('roles', 'is_new'))) && (empty($user_fields[$key]) && empty($field_form[$key])) && ($value !== NULL)) {
+	        $data[$key] = $value;
+	      }
+	    }
+	    if (!empty($data)) {
+	      $data_array = array('uid' => $user->uid, 'data' => $data);
+	      drupal_write_record('users', $data_array, 'uid');
+	    }
+
+	    // Save user roles (delete just to be safe).
+	    if (isset($edit['roles']) && is_array($edit['roles'])) {
+	      db_delete('users_roles')
+	        ->condition('uid', $edit['uid'])
+	        ->execute();
+	      $query = db_insert('users_roles')->fields(array('uid', 'rid'));
+	      foreach (array_keys($edit['roles']) as $rid) {
+	        if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
+	          $query->values(array(
+	            'uid' => $edit['uid'],
+	            'rid' => $rid,
+	          ));
+	        }
+	      }
+	      $query->execute();
+	    }
+
+	    // Build the finished user object.
+	    $user = user_load($edit['uid'], TRUE);
+	  }
+
+	  return $user;
+  }
+  catch (Exception $e) {
+    $transaction->rollback();
+    watchdog('node', $e->getMessage(), array(), WATCHDOG_WARNING);
+    // If the user object could not be saved for whatever reason,
+    // return NULL instead so that the caller knows it didn't work.
   }
-
-  // Get the fields form so we can recognize the fields in the $edit
-  // form that should not go into the serialized data array.
-  $field_form = array();
-  $field_form_state = array();
-  $edit = (object) $edit;
-  field_attach_form('user', $edit, $field_form, $field_form_state);
-
-  // Presave fields.
-  field_attach_presave('user', $edit);
-
-  $edit = (array) $edit;
-
-  if (!isset($account->is_new)) {
-    $account->is_new = empty($account->uid);
-  }
-  if (is_object($account) && !$account->is_new) {
-    user_module_invoke('update', $edit, $account, $category);
-    $data = unserialize(db_query('SELECT data FROM {users} WHERE uid = :uid', array(':uid' => $account->uid))->fetchField());
-    // Consider users edited by an administrator as logged in, if they haven't
-    // already, so anonymous users can view the profile (if allowed).
-    if (empty($edit['access']) && empty($account->access) && user_access('administer users')) {
-      $edit['access'] = REQUEST_TIME;
-    }
-    foreach ($edit as $key => $value) {
-      // Form fields that don't pertain to the users, user_roles, or
-      // Field API are automatically serialized into the users.data
-      // column.
-      if (!in_array($key, array('roles', 'is_new')) && empty($user_fields[$key]) && empty($field_form[$key])) {
-        if ($value === NULL) {
-          unset($data[$key]);
-        }
-        else {
-          $data[$key] = $value;
-        }
-      }
-    }
-
-    // Process picture uploads.
-    if (!empty($edit['picture']->fid)) {
-      $picture = $edit['picture'];
-      // If the picture is a temporary file move it to its final location and
-      // make it permanent.
-      if (($picture->status & FILE_STATUS_PERMANENT) == 0) {
-        $info = image_get_info($picture->uri);
-        $picture_directory =  variable_get('file_default_scheme', 'public') . '://' . variable_get('user_picture_path', 'pictures');
-
-        // Prepare the pictures directory.
-        file_prepare_directory($picture_directory, FILE_CREATE_DIRECTORY);
-        $destination = file_stream_wrapper_uri_normalize($picture_directory . '/picture-' . $account->uid . '.' . $info['extension']);
-
-        if ($picture = file_move($picture, $destination, FILE_EXISTS_REPLACE)) {
-          $picture->status |= FILE_STATUS_PERMANENT;
-          $edit['picture'] = file_save($picture);
-        }
-      }
-    }
-    $edit['picture'] = empty($edit['picture']->fid) ? 0 : $edit['picture']->fid;
-
-    $edit['data'] = $data;
-    // Do not allow 'uid' to be changed.
-    $edit['uid'] = $account->uid;
-    // Save changes to the user table.
-    $success = drupal_write_record('users', $edit, 'uid');
-    if (!$success) {
-      // The query failed - better to abort the save than risk further
-      // data loss.
-
-      // TODO: Fields change: I think this is a bug.  If no columns in
-      // the user table are changed, drupal_write_record returns
-      // FALSE because rowCount() (rows changed) is 0.  However,
-      // non-users data may have been changed, e.g. fields.
-      // return FALSE;
-    }
-
-    // If the picture changed or was unset, remove the old one. This step needs
-    // to occur after updating the {users} record so that user_file_references()
-    // doesn't report it in use and block the deletion.
-    if (!empty($account->picture->fid) && ($edit['picture'] != $account->picture->fid)) {
-      file_delete($account->picture);
-    }
-
-    // Reload user roles if provided.
-    if (isset($edit['roles']) && is_array($edit['roles'])) {
-      db_delete('users_roles')
-        ->condition('uid', $account->uid)
-        ->execute();
-
-      $query = db_insert('users_roles')->fields(array('uid', 'rid'));
-      foreach (array_keys($edit['roles']) as $rid) {
-        if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
-          $query->values(array(
-            'uid' => $account->uid,
-            'rid' => $rid,
-          ));
-        }
-      }
-      $query->execute();
-    }
-
-    // Delete a blocked user's sessions to kick them if they are online.
-    if (isset($edit['status']) && $edit['status'] == 0) {
-      drupal_session_destroy_uid($account->uid);
-    }
-
-    // If the password changed, delete all open sessions and recreate
-    // the current one.
-    if (!empty($edit['pass'])) {
-      drupal_session_destroy_uid($account->uid);
-      if ($account->uid == $GLOBALS['user']->uid) {
-        drupal_session_regenerate();
-      }
-    }
-
-    // Save Field data.
-    $object = (object) $edit;
-    field_attach_update('user', $object);
-
-    // Refresh user object.
-    $user = user_load($account->uid, TRUE);
-
-    // Send emails after we have the new user object.
-    if (isset($edit['status']) && $edit['status'] != $account->status) {
-      // The user's status is changing; conditionally send notification email.
-      $op = $edit['status'] == 1 ? 'status_activated' : 'status_blocked';
-      _user_mail_notify($op, $user);
-    }
-
-    user_module_invoke('after_update', $edit, $user, $category);
-  }
-  else {
-    // Allow 'created' to be set by the caller.
-    if (!isset($edit['created'])) {
-      $edit['created'] = REQUEST_TIME;
-    }
-    // Consider users created by an administrator as already logged in, so
-    // anonymous users can view the profile (if allowed).
-    if (empty($edit['access']) && user_access('administer users')) {
-      $edit['access'] = REQUEST_TIME;
-    }
-
-    $edit['mail'] = trim($edit['mail']);
-    $success = drupal_write_record('users', $edit);
-    if (!$success) {
-      // On a failed INSERT some other existing user's uid may be returned.
-      // We must abort to avoid overwriting their account.
-      return FALSE;
-    }
-
-    // Build the initial user object.
-    $user = user_load($edit['uid'], TRUE);
-
-    $object = (object) $edit;
-    field_attach_insert('user', $object);
-
-    user_module_invoke('insert', $edit, $user, $category);
-
-    // Note, we wait with saving the data column to prevent module-handled
-    // fields from being saved there.
-    $data = array();
-    foreach ($edit as $key => $value) {
-      // Form fields that don't pertain to the users, user_roles, or
-      // Field API are automatically serialized into the user.data
-      // column.
-      if ((!in_array($key, array('roles', 'is_new'))) && (empty($user_fields[$key]) && empty($field_form[$key])) && ($value !== NULL)) {
-        $data[$key] = $value;
-      }
-    }
-    if (!empty($data)) {
-      $data_array = array('uid' => $user->uid, 'data' => $data);
-      drupal_write_record('users', $data_array, 'uid');
-    }
-
-    // Save user roles (delete just to be safe).
-    if (isset($edit['roles']) && is_array($edit['roles'])) {
-      db_delete('users_roles')
-        ->condition('uid', $edit['uid'])
-        ->execute();
-      $query = db_insert('users_roles')->fields(array('uid', 'rid'));
-      foreach (array_keys($edit['roles']) as $rid) {
-        if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
-          $query->values(array(
-            'uid' => $edit['uid'],
-            'rid' => $rid,
-          ));
-        }
-      }
-      $query->execute();
-    }
-
-    // Build the finished user object.
-    $user = user_load($edit['uid'], TRUE);
-  }
-
-  return $user;
 }
 
 /**
@@ -2057,7 +2069,7 @@ function _user_cancel($edit, $account, $
  *   The user account of the profile being viewed.
  *
  * To theme user profiles, copy modules/user/user-profile.tpl.php
- * to your theme directory, and edit it as instructed in that file's comments. 
+ * to your theme directory, and edit it as instructed in that file's comments.
  *
  * @param $account
  *   A user object.
@@ -2072,7 +2084,7 @@ function user_build($account) {
   $build = $account->content;
   // We don't need duplicate rendering info in account->content.
   unset($account->content);
-  
+
   $build += array(
     '#theme' => 'user_profile',
     '#account' => $account,

