You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2018/01/19 16:07:16 UTC

svn commit: r1821678 - /subversion/trunk/subversion/libsvn_client/shelve.c

Author: julianfoad
Date: Fri Jan 19 16:07:16 2018
New Revision: 1821678

URL: http://svn.apache.org/viewvc?rev=1821678&view=rev
Log:
Encode the shelf name to ensure a valid filename for the patch file.

* subversion/libsvn_client/shelve.c
  (shelf_name_encode,
   shelf_name_decode,
   shelf_name_from_filename): New.
  (get_patch_abspath): Encode.
  (svn_client_shelves_list): Decode; ignore unrecognized filenames.
  (validate_name): Delete this function and the calls to it.

Modified:
    subversion/trunk/subversion/libsvn_client/shelve.c

Modified: subversion/trunk/subversion/libsvn_client/shelve.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/shelve.c?rev=1821678&r1=1821677&r2=1821678&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/shelve.c (original)
+++ subversion/trunk/subversion/libsvn_client/shelve.c Fri Jan 19 16:07:16 2018
@@ -34,6 +34,7 @@
 #include "svn_path.h"
 #include "svn_hash.h"
 #include "svn_utf.h"
+#include "svn_ctype.h"
 
 #include "client.h"
 #include "private/svn_client_private.h"
@@ -41,15 +42,66 @@
 #include "svn_private_config.h"
 
 
-/* Throw an error if NAME does not conform to our naming rules. */
 static svn_error_t *
-validate_name(const char *name,
-              apr_pool_t *scratch_pool)
+shelf_name_encode(char **encoded_name_p,
+                  const char *name,
+                  apr_pool_t *result_pool)
 {
-  if (name[0] == '\0' || strchr(name, '/'))
-    return svn_error_createf(SVN_ERR_BAD_CHANGELIST_NAME, NULL,
-                             _("Shelve: Bad name '%s'"), name);
+  char *encoded_name
+    = apr_palloc(result_pool, strlen(name) * 2 + 1);
+  char *out_pos = encoded_name;
+
+  if (name[0] == '\0')
+    return svn_error_create(SVN_ERR_BAD_CHANGELIST_NAME, NULL,
+                            _("Shelf name cannot be the empty string"));
 
+  while (*name)
+    {
+      apr_snprintf(out_pos, 3, "%02x", *name++);
+      out_pos += 2;
+    }
+  *encoded_name_p = encoded_name;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+shelf_name_decode(char **decoded_name_p,
+                  const char *codename,
+                  apr_pool_t *result_pool)
+{
+  svn_stringbuf_t *sb
+    = svn_stringbuf_create_ensure(strlen(codename) / 2, result_pool);
+  const char *input = codename;
+
+  while (*input)
+    {
+      int c;
+      int nchars;
+      int nitems = sscanf(input, "%02x%n", &c, &nchars);
+
+      if (nitems != 1 || nchars != 2)
+        return svn_error_createf(SVN_ERR_BAD_CHANGELIST_NAME, NULL,
+                                 _("Shelve: Bad encoded name '%s'"), codename);
+      svn_stringbuf_appendbyte(sb, c);
+      input += 2;
+    }
+  *decoded_name_p = sb->data;
+  return SVN_NO_ERROR;
+}
+
+/* Set *NAME to the shelf name from FILENAME. */
+static svn_error_t *
+shelf_name_from_filename(char **name,
+                         const char *filename,
+                         apr_pool_t *result_pool)
+{
+  size_t len = strlen(filename);
+
+  if (len > 6 && strcmp(filename + len - 6, ".patch") == 0)
+    {
+      char *codename = apr_pstrndup(result_pool, filename, len - 6);
+      SVN_ERR(shelf_name_decode(name, codename, result_pool));
+    }
   return SVN_NO_ERROR;
 }
 
@@ -65,11 +117,12 @@ get_patch_abspath(char **patch_abspath,
                   apr_pool_t *scratch_pool)
 {
   char *dir;
-  const char *filename;
+  char *filename;
 
   SVN_ERR(svn_wc__get_shelves_dir(&dir, ctx->wc_ctx, wc_root_abspath,
                                   scratch_pool, scratch_pool));
-  filename = apr_pstrcat(scratch_pool, name, ".patch", SVN_VA_NULL);
+  SVN_ERR(shelf_name_encode(&filename, name, scratch_pool));
+  filename = apr_pstrcat(scratch_pool, filename, ".patch", SVN_VA_NULL);
   *patch_abspath = svn_dirent_join(dir, filename, result_pool);
   return SVN_NO_ERROR;
 }
@@ -240,8 +293,6 @@ svn_client_shelve(const char *name,
   const char *message = "";
   svn_error_t *err;
 
-  SVN_ERR(validate_name(name, pool));
-
   /* ### TODO: check all paths are in same WC; for now use first path */
   SVN_ERR(svn_dirent_get_absolute(&local_abspath,
                                   APR_ARRAY_IDX(paths, 0, char *), pool));
@@ -302,8 +353,6 @@ svn_client_unshelve(const char *name,
   const char *wc_root_abspath;
   svn_error_t *err;
 
-  SVN_ERR(validate_name(name, pool));
-
   SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
                                  local_abspath, ctx, pool, pool));
 
@@ -339,8 +388,6 @@ svn_client_shelves_delete(const char *na
 {
   const char *wc_root_abspath;
 
-  SVN_ERR(validate_name(name, pool));
-
   SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
                                  local_abspath, ctx, pool, pool));
 
@@ -378,8 +425,6 @@ svn_client_shelf_get_paths(apr_hash_t **
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   apr_hash_t *paths = apr_hash_make(result_pool);
 
-  SVN_ERR(validate_name(name, scratch_pool));
-
   SVN_ERR(svn_client_get_wc_root(&wc_root_abspath,
                                  local_abspath, ctx, scratch_pool, scratch_pool));
   SVN_ERR(get_patch_abspath(&patch_abspath, name, wc_root_abspath,
@@ -469,15 +514,16 @@ svn_client_shelves_list(apr_hash_t **she
   for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
     {
       const char *filename = apr_hash_this_key(hi);
-      size_t len = strlen(filename);
+      svn_io_dirent2_t *dirent = apr_hash_this_val(hi);
+      char *name = NULL;
 
-      if (len > 6 && strcmp(filename + len - 6, ".patch") == 0)
+      svn_error_clear(shelf_name_from_filename(&name, filename, result_pool));
+      if (name && dirent->kind == svn_node_file)
         {
-          const char *name = apr_pstrndup(result_pool, filename, len - 6);
           svn_client_shelved_patch_info_t *info
             = apr_palloc(result_pool, sizeof(*info));
 
-          info->dirent = apr_hash_this_val(hi);
+          info->dirent = dirent;
           info->mtime = info->dirent->mtime;
           info->patch_path
             = svn_dirent_join(shelves_dir, filename, result_pool);