Merge branch '3251-remove-filename-rootname'
diff --git a/src/couch_db.erl b/src/couch_db.erl
index 3955d8b..e45b20d 100644
--- a/src/couch_db.erl
+++ b/src/couch_db.erl
@@ -1519,15 +1519,7 @@
 normalize_dbname(DbName) when is_list(DbName) ->
     normalize_dbname(list_to_binary(DbName));
 normalize_dbname(DbName) when is_binary(DbName) ->
-    mem3:dbname(maybe_remove_extension(DbName)).
-
-maybe_remove_extension(DbName) ->
-    case filename:extension(DbName) of
-        <<".couch">> ->
-            filename:rootname(DbName);
-        _ ->
-            DbName
-    end.
+    mem3:dbname(couch_util:drop_dot_couch_ext(DbName)).
 
 
 -spec dbname_suffix(list() | binary()) -> binary().
@@ -1544,7 +1536,7 @@
         DbName, Normalized, fun validate_dbname_int/2).
 
 validate_dbname_int(DbName, Normalized) when is_binary(DbName) ->
-    DbNoExt = maybe_remove_extension(DbName),
+    DbNoExt = couch_util:drop_dot_couch_ext(DbName),
     case re:run(DbNoExt, ?DBNAME_REGEX, [{capture,none}, dollar_endonly]) of
         match ->
             ok;
diff --git a/src/couch_server.erl b/src/couch_server.erl
index b60017a..59bffa5 100644
--- a/src/couch_server.erl
+++ b/src/couch_server.erl
@@ -261,7 +261,7 @@
                 [$/ | RelativeFilename] -> ok;
                 RelativeFilename -> ok
                 end,
-                case Fun(?l2b(filename:rootname(RelativeFilename, ".couch")), AccIn) of
+                case Fun(couch_util:drop_dot_couch_ext(?l2b(RelativeFilename)), AccIn) of
                 {ok, NewAcc} -> NewAcc;
                 {stop, NewAcc} -> throw({stop, Fun, NewAcc})
                 end
diff --git a/src/couch_util.erl b/src/couch_util.erl
index 9593451..6001ae2 100644
--- a/src/couch_util.erl
+++ b/src/couch_util.erl
@@ -15,7 +15,7 @@
 -export([priv_dir/0, normpath/1]).
 -export([should_flush/0, should_flush/1, to_existing_atom/1]).
 -export([rand32/0, implode/2, collate/2, collate/3]).
--export([abs_pathname/1,abs_pathname/2, trim/1]).
+-export([abs_pathname/1,abs_pathname/2, trim/1, drop_dot_couch_ext/1]).
 -export([encodeBase64Url/1, decodeBase64Url/1]).
 -export([validate_utf8/1, to_hex/1, parse_term/1, dict_find/3]).
 -export([get_nested_json_value/2, json_user_ctx/1]).
@@ -257,6 +257,20 @@
     String2 = lists:dropwhile(fun is_whitespace/1, String),
     lists:reverse(lists:dropwhile(fun is_whitespace/1, lists:reverse(String2))).
 
+
+drop_dot_couch_ext(DbName) when is_binary(DbName) ->
+    PrefixLen = size(DbName) - 6,
+    case DbName of
+        <<Prefix:PrefixLen/binary, ".couch">> ->
+            Prefix;
+        Else ->
+            Else
+    end;
+
+drop_dot_couch_ext(DbName) when is_list(DbName) ->
+    binary_to_list(drop_dot_couch_ext(iolist_to_binary(DbName))).
+
+
 % takes a heirarchical list of dirs and removes the dots ".", double dots
 % ".." and the corresponding parent dirs.
 fix_path_list([], Acc) ->