From ebd778c519376d78b2e2e98c97c13e4cbe1748c0 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Thu, 1 Aug 2013 15:15:49 -0400 Subject: [PATCH] Escape ':' in file/directory names to avoid it being treated as a pathspec by some git commands A git pathspec is a filename, except when it starts with ':', it's taken to refer to a branch, etc. Rather than special case ':', any filename starting with anything unusual is prefixed with "./" This could have been a real mess to deal with, but luckily SafeCommand is already extensively used and so we know at the type level the difference between parameters that are files, and parameters that are command options. Testing did show that Git.Queue was not using SafeCommand on filenames fed to xargs. (Filenames starting with '-' worked before only because -- was used to separate filenames from options when calling eg git add.) The test suite now passes with filenames starting with ':'. However, I did not keep that change to it, because such filenames are probably not legal on windows, and I have enough ugly windows ifdefs in there as it is. This commit was sponsored by Otavio Salvador. Thanks! --- Git/Queue.hs | 6 +++--- Utility/SafeCommand.hs | 16 +++++++++++----- debian/changelog | 2 ++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Git/Queue.hs b/Git/Queue.hs index d88c71880a..b8e863658a 100644 --- a/Git/Queue.hs +++ b/Git/Queue.hs @@ -40,7 +40,7 @@ data Action | CommandAction { getSubcommand :: String , getParams :: [CommandParam] - , getFiles :: [FilePath] + , getFiles :: [CommandParam] } {- A key that can uniquely represent an action in a Map. -} @@ -92,7 +92,7 @@ addCommand subcommand params files q repo = , getParams = params , getFiles = newfiles } - newfiles = files ++ maybe [] getFiles (M.lookup key $ items q) + newfiles = map File files ++ maybe [] getFiles (M.lookup key $ items q) different (CommandAction { getSubcommand = s }) = s /= subcommand different _ = True @@ -150,7 +150,7 @@ runAction repo (UpdateIndexAction streamers) = runAction repo action@(CommandAction {}) = withHandle StdinHandle createProcessSuccess p $ \h -> do fileEncoding h - hPutStr h $ intercalate "\0" $ getFiles action + hPutStr h $ intercalate "\0" $ toCommand $ getFiles action hClose h where p = (proc "xargs" params) { env = gitEnv repo } diff --git a/Utility/SafeCommand.hs b/Utility/SafeCommand.hs index 785aec5781..d24c75dd48 100644 --- a/Utility/SafeCommand.hs +++ b/Utility/SafeCommand.hs @@ -1,6 +1,6 @@ {- safely running shell commands - - - Copyright 2010-2012 Joey Hess + - Copyright 2010-2013 Joey Hess - - Licensed under the GNU GPL version 3 or higher. -} @@ -12,6 +12,8 @@ import Utility.Process import System.Process (env) import Data.String.Utils import Control.Applicative +import System.FilePath +import Data.Char {- A type for parameters passed to a shell command. A command can - be passed either some Params (multiple parameters can be included, @@ -24,14 +26,18 @@ data CommandParam = Params String | Param String | File FilePath {- Used to pass a list of CommandParams to a function that runs - a command and expects Strings. -} toCommand :: [CommandParam] -> [String] -toCommand = (>>= unwrap) +toCommand = concatMap unwrap where unwrap (Param s) = [s] unwrap (Params s) = filter (not . null) (split " " s) - -- Files that start with a dash are modified to avoid - -- the command interpreting them as options. - unwrap (File s@('-':_)) = ["./" ++ s] + -- Files that start with a non-alphanumeric that is not a path + -- separator are modified to avoid the command interpreting them as + -- options or other special constructs. + unwrap (File s@(h:_)) + | isAlphaNum h || h `elem` pathseps = [s] + | otherwise = ["./" ++ s] unwrap (File s) = [s] + pathseps = [pathSeparator, '.'] {- Run a system command, and returns True or False - if it succeeded or failed. diff --git a/debian/changelog b/debian/changelog index 4792161657..b5d1211b7f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -37,6 +37,8 @@ git-annex (4.20130724) UNRELEASED; urgency=low * Fix a few bugs involving filenames that are at or near the filesystem's maximum filename length limit. * find: Avoid polluting stdout with progress messages. Closes: #718186 + * Escape ':' in file/directory names to avoid it being treated + as a pathspec by some git commands. Closes: #718185 -- Joey Hess Tue, 23 Jul 2013 12:39:48 -0400