You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by da...@apache.org on 2013/03/27 03:16:44 UTC

svn commit: r1461389 - /subversion/trunk/tools/hook-scripts/control-chars.py

Author: danielsh
Date: Wed Mar 27 02:16:44 2013
New Revision: 1461389

URL: http://svn.apache.org/r1461389
Log:
Add a hook script that rejects filenames that contain control characters.

This is needed at least for filenames that contain newlines;
tools/hook-scripts/validate-files.py can't handle those since svnlook's output
is not parseable in that case.

Thread: http://mid.gmane.org/CADkdwvRfkX=-b_wb8S-NqUD3r9V=omdHqd9eOX0iumuojRM0og@mail.gmail.com

Patch by: breser

* tools/hook-scripts/control-chars.py: New script.

Added:
    subversion/trunk/tools/hook-scripts/control-chars.py

Added: subversion/trunk/tools/hook-scripts/control-chars.py
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/hook-scripts/control-chars.py?rev=1461389&view=auto
==============================================================================
--- subversion/trunk/tools/hook-scripts/control-chars.py (added)
+++ subversion/trunk/tools/hook-scripts/control-chars.py Wed Mar 27 02:16:44 2013
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+#
+
+# control-chars.py: Reject filenames that have control characters. 
+
+import sys
+import re
+import posixpath
+
+import svn
+import svn.fs
+import svn.repos
+import svn.core
+
+control_chars = set()
+for i in range(1, 32):
+  control_chars.add(chr(i))
+control_chars.add(chr(127))
+
+def check_tree(node, path):
+  "Walk the node checking for control characters"
+  if not node:
+    return 0
+ 
+  if node.action == 'A':
+    if any((c in control_chars) for c in node.name):
+      sys.stderr.write("'%s' contains a control character" % path)
+      return 3
+
+  node = node.child
+  if not node:
+    return 0
+
+  while node:
+    full_path = posixpath.join(path, node.name)
+    ret_val = check_tree(node, full_path)
+    # If we ran into an error just return up the stack all the way
+    if ret_val > 0:
+      return ret_val 
+    node = node.sibling
+
+  return 0 
+
+def usage():
+  sys.stderr.write("Invalid arguments, expects to be called like a pre-commit hook.")
+
+def main(ignored_pool, argv):
+  if len(argv) < 3:
+    usage()
+    return 2
+
+  repos_path = svn.core.svn_path_canonicalize(argv[1])
+  txn_name = argv[2] 
+  
+  if not repos_path or not txn_name:
+    usage() 
+    return 2
+
+  repos = svn.repos.svn_repos_open(repos_path)
+  fs = svn.repos.svn_repos_fs(repos)
+  txn = svn.fs.svn_fs_open_txn(fs, txn_name)
+  txn_root = svn.fs.svn_fs_txn_root(txn)
+  base_rev = svn.fs.svn_fs_txn_base_revision(txn)
+  if not base_rev or base_rev <= svn.core.SVN_INVALID_REVNUM: 
+    sys.stderr.write("Transaction '%s' is not based on a revision" % txn_name)
+    return 2
+  base_root = svn.fs.svn_fs_revision_root(fs, base_rev)
+  editor, editor_baton = svn.repos.svn_repos_node_editor(repos, base_root,
+                                                         txn_root)
+  try:
+    svn.repos.svn_repos_replay2(txn_root, "", svn.core.SVN_INVALID_REVNUM,
+                                False, editor, editor_baton, None, None)
+  except svn.core.SubversionException as e:
+    # If we get a file not found error then some file has a newline in it and
+    # fsfs's own transaction is now corrupted.
+    if e.apr_err == svn.core.SVN_ERR_FS_NOT_FOUND:
+      path = re.search("path '(.*?)'", e.message).group(1)
+      sys.stderr.write("Path name that contains '%s' has a newline." % path)
+      return 3
+    # fs corrupt error probably means that there is probably both
+    # file and file\n in the transaction.  However, we can't really determine
+    # which files since the transaction is broken.  Even if we didn't reject
+    # this it would not be able to be committed.  This just gives a better
+    # error message.
+    elif e.apr_err == svn.core.SVN_ERR_FS_CORRUPT:
+      sys.stderr.write("Some path contains a newline causing: %s" % repr(e))
+      return 3
+    else:
+      sys.stderr.write(repr(e))
+      return 2
+  tree = svn.repos.svn_repos_node_from_baton(editor_baton)
+  return check_tree(tree, "/")
+
+if __name__ == '__main__':
+  sys.exit(svn.core.run_app(main, sys.argv))