Author: rhuijben
Date: Tue Jul  5 14:17:22 2011
New Revision: 1143071

URL: http://svn.apache.org/viewvc?rev=1143071&view=rev
Log:
Make svn update handle some access denied scenarios with a proper skip. This
makes it less likely that the database will be closed after updating with
working queue items left.

* 
subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientNotifyInformation.java
  (Action): Add new value

* subversion/include/svn_error_codes.h
  (SVN_ERR_WC_PATH_ACCESS_DENIED): New error code.

* subversion/include/svn_wc.h
  (svn_wc_notify_action_t): Add new value.

* subversion/libsvn_wc/questions.c
  (svn_wc__internal_file_modified_p): Wrap EACCESS errors with
    SVN_ERR_WC_PATH_ACCESS_DENIED to allow callers to check for this condition
    versus any access denied.

* subversion/libsvn_wc/status.c
  (assemble_status): Handle the new error code instead of all access denied
    errors.

* subversion/libsvn_wc/update_editor.c
  (close_file): Handle the access denied error with a proper skip. Call the
    notification handler.

* subversion/svn/notify.c
  (notify): Handle the new skip action.

* subversion/tests/cmdline/update_tests.py
  (skip_access_denied): New windows-only test that tests access denied in
    update and status.
  (test_list): Add skip_access_denied.

Modified:
    
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientNotifyInformation.java
    subversion/trunk/subversion/include/svn_error_codes.h
    subversion/trunk/subversion/include/svn_wc.h
    subversion/trunk/subversion/libsvn_wc/questions.c
    subversion/trunk/subversion/libsvn_wc/status.c
    subversion/trunk/subversion/libsvn_wc/update_editor.c
    subversion/trunk/subversion/svn/notify.c
    subversion/trunk/subversion/tests/cmdline/update_tests.py

Modified: 
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientNotifyInformation.java
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientNotifyInformation.java?rev=1143071&r1=1143070&r2=1143071&view=diff
==============================================================================
--- 
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientNotifyInformation.java
 (original)
+++ 
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ClientNotifyInformation.java
 Tue Jul  5 14:17:22 2011
@@ -468,6 +468,9 @@ public class ClientNotifyInformation ext
         /** Skipping a working only node */
         update_skip_working_only ("update skip working only"),
 
+        /** Skipped a file or directory to which access couldn't be obtained */
+        update_skip_access_denied ("update skip access denied"),
+
         /** An update operation removed an external working copy.  */
         update_external_removed ("update external removed"),
 

Modified: subversion/trunk/subversion/include/svn_error_codes.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_error_codes.h?rev=1143071&r1=1143070&r2=1143071&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_error_codes.h (original)
+++ subversion/trunk/subversion/include/svn_error_codes.h Tue Jul  5 14:17:22 
2011
@@ -530,6 +530,11 @@ SVN_ERROR_START
              SVN_ERR_WC_CATEGORY_START + 38,
              "This operation can not be performed with just this depth.")
 
+  /** @since New in 1.7. */
+  SVN_ERRDEF(SVN_ERR_WC_PATH_ACCESS_DENIED,
+             SVN_ERR_WC_CATEGORY_START + 39,
+             "Couldn't open a working copy file because access was denied")
+
   /* fs errors */
 
   SVN_ERRDEF(SVN_ERR_FS_GENERAL,

Modified: subversion/trunk/subversion/include/svn_wc.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_wc.h?rev=1143071&r1=1143070&r2=1143071&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_wc.h (original)
+++ subversion/trunk/subversion/include/svn_wc.h Tue Jul  5 14:17:22 2011
@@ -1107,6 +1107,10 @@ typedef enum svn_wc_notify_action_t
    * @since New in 1.7. */
   svn_wc_notify_update_skip_working_only,
 
+  /** An update tried to update a file or directory to which access could
+   * not be obtained. @since New in 1.7. */
+  svn_wc_notify_update_skip_access_denied,
+
   /** An update operation removed an external working copy.
    * @since New in 1.7. */
   svn_wc_notify_update_external_removed,

Modified: subversion/trunk/subversion/libsvn_wc/questions.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/questions.c?rev=1143071&r1=1143070&r2=1143071&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/questions.c (original)
+++ subversion/trunk/subversion/libsvn_wc/questions.c Tue Jul  5 14:17:22 2011
@@ -335,12 +335,22 @@ svn_wc__internal_file_modified_p(svn_boo
                                    scratch_pool, scratch_pool));
 
   /* Check all bytes, and verify checksum if requested. */
-  SVN_ERR(compare_and_verify(modified_p, db,
+  {
+    svn_error_t *err;
+    err = compare_and_verify(modified_p, db,
                              local_abspath, dirent->filesize,
                              pristine_stream, pristine_size,
                              has_props, props_mod,
                              exact_comparison,
-                             scratch_pool));
+                             scratch_pool);
+
+    /* At this point we already opened the pristine file, so we know that
+       the access denied applies to the working copy path */
+    if (err && APR_STATUS_IS_EACCES(err->apr_err))
+      return svn_error_create(SVN_ERR_WC_PATH_ACCESS_DENIED, err, NULL);
+    else
+      SVN_ERR(err);
+  }
 
   if (!*modified_p)
     {

Modified: subversion/trunk/subversion/libsvn_wc/status.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/status.c?rev=1143071&r1=1143070&r2=1143071&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/status.c (original)
+++ subversion/trunk/subversion/libsvn_wc/status.c Tue Jul  5 14:17:22 2011
@@ -537,7 +537,7 @@ assemble_status(svn_wc_status3_t **statu
 
               if (err)
                 {
-                  if (!APR_STATUS_IS_EACCES(err->apr_err))
+                  if (err->apr_err != SVN_ERR_WC_PATH_ACCESS_DENIED)
                     return svn_error_trace(err);
 
                   /* An access denied is very common on Windows when another

Modified: subversion/trunk/subversion/libsvn_wc/update_editor.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/update_editor.c?rev=1143071&r1=1143070&r2=1143071&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/update_editor.c Tue Jul  5 14:17:22 
2011
@@ -4114,9 +4114,37 @@ close_file(void *file_baton,
       /* Merge the text. This will queue some additional work.  */
       if (!fb->obstruction_found)
         {
-          SVN_ERR(merge_file(&work_item, &install_pristine, &install_from,
-                             &content_state, fb, current_actual_props,
-                             fb->changed_date, scratch_pool, scratch_pool));
+          svn_error_t *err;
+          err = merge_file(&work_item, &install_pristine, &install_from,
+                           &content_state, fb, current_actual_props,
+                           fb->changed_date, scratch_pool, scratch_pool);
+
+          if (err && err->apr_err == SVN_ERR_WC_PATH_ACCESS_DENIED)
+            {
+              if (eb->notify_func)
+                {
+                  svn_wc_notify_t *notify =svn_wc_create_notify(
+                                fb->local_abspath,
+                                svn_wc_notify_update_skip_access_denied,
+                                scratch_pool);
+
+                  notify->kind = svn_node_file;
+                  notify->err = err;
+
+                  eb->notify_func(eb->notify_baton, notify, scratch_pool);
+                }
+              svn_error_clear(err);
+
+              SVN_ERR(remember_skipped_tree(eb, fb->local_abspath,
+                                            scratch_pool));
+              fb->skip_this = TRUE;
+
+              SVN_ERR(maybe_release_dir_info(fb->bump_info));
+              svn_pool_destroy(fb->pool);
+              return SVN_NO_ERROR;
+            }
+          else
+            SVN_ERR(err);
 
           all_work_items = svn_wc__wq_merge(all_work_items, work_item,
                                             scratch_pool);

Modified: subversion/trunk/subversion/svn/notify.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/notify.c?rev=1143071&r1=1143070&r2=1143071&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/notify.c (original)
+++ subversion/trunk/subversion/svn/notify.c Tue Jul  5 14:17:22 2011
@@ -162,6 +162,13 @@ notify(void *baton, const svn_wc_notify_
             path_local)))
         goto print_error;
       break;
+    case svn_wc_notify_update_skip_access_denied:
+      nb->skipped_paths++;
+      if ((err = svn_cmdline_printf(
+            pool, _("Skipped '%s' -- Access denied\n"),
+            path_local)))
+        goto print_error;
+      break;
     case svn_wc_notify_update_delete:
     case svn_wc_notify_exclude:
       nb->received_some_change = TRUE;

Modified: subversion/trunk/subversion/tests/cmdline/update_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/update_tests.py?rev=1143071&r1=1143070&r2=1143071&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/update_tests.py Tue Jul  5 
14:17:22 2011
@@ -5342,6 +5342,57 @@ def revive_children_of_copy(sbox):
   if not os.path.exists(psi2_path):
     raise svntest.Failure('psi unexpectedly non-existent')
 
+@SkipUnless(svntest.main.is_os_windows)
+def skip_access_denied(sbox):
+  """access denied paths should be skipped"""
+
+  # We need something to lock the file. 'msvcrt' looks common on Windows
+  try:
+    import msvcrt
+  except ImportError:
+    raise svntest.Skip
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  iota = sbox.ospath('iota')
+
+  svntest.main.file_write(iota, 'Q')
+  sbox.simple_commit()
+  sbox.simple_update() # Update to r2
+
+  # Open iota for writing to keep an handle open
+  f = open(iota, 'w')
+
+  # Write new text of exactly the same size to avoid the early out
+  # on a different size without properties.
+  f.write('R')
+  f.flush()
+
+  # And lock the first byte of the file
+  msvcrt.locking(f.fileno(), 1, 1)
+
+  expected_output = svntest.wc.State(wc_dir, {
+    'iota' : Item(verb='Skipped'),
+    })
+
+  # Create expected status tree: iota isn't updated
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('iota', status='M ', wc_rev=2)
+
+  # And now check that update skips the path
+  # *and* status shows the path as modified.
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        None,
+                                        expected_status,
+                                        None,
+                                        None, None,
+                                        None, None, None, wc_dir, '-r', '1')
+
+  f.close()
+
+
 
 #######################################################################
 # Run the tests
@@ -5407,6 +5458,7 @@ test_list = [ None,
               update_with_file_lock_and_keywords_property_set,
               update_nonexistent_child_of_copy,
               revive_children_of_copy,
+              skip_access_denied,
              ]
 
 if __name__ == '__main__':


Reply via email to