Search code examples
svnescapingquotescmdampersand

svn pre-lock hook processing flaw with ampersand and spaces in filename on windows


I am trying to create a subversion pre-lock hook on windows. However I have serious problems with ampersand in filenames:

It seems svn will place double quotes(") around my file-to-be-locked in my call to my batch file, if the path contains spaces. However If my filename contains ampersand (&) and no spaces there are no double quotes and windows think it is a second call and my script does not get the correct filename.

As you can see in logfile, I cannot handle ampersand correctly because windows command.com is interpreting the escaped quotes the same as the non escaped:

>perl pre-lock.pl repo \""one & two"\" name

will always fail with "'two' is not recognized as an internal or external command, operable program or batch file."

Is this an Error in command.com?

For reference and self trying, here are my files:

@echo off
echo %1 %2 %3 >> c:\hooktest.txt
set SCRIPTS=c:/scripts
SET PERL=C:/Perl/bin/perl.exe
%PERL% -w -I%SCRIPTS% "%SCRIPTS%/pre-lock.pl" \"%1\" \"%2\" \"%\3\"
set err=%errorlevel%
exit %err% 

a small debug perl script:

use Data::Dumper;
 print STDERR "This are the arguments:\n";
 print STDERR Dumper(@ARGV);
 exit 1;

In my Hook log the following is logged:

c:\repo /test/file_nospace.txt pparker 
c:\repo "/test/file with space" pparker 
c:\repo "/test/file with & ampersand.txt" pparker 
c:\repo /test/file_with_&_ampersand.txt pparker 

Solution

  • First of all, this has (hopefully) nothing to do with command.com, as cmd.exe is executing batch files.

    Nevertheless, yes, the shell quotes differently. It is no Unix shell and does not have to adhere to conventions there.

    I wonder though, why you need two levels of quotes there. Putting a single level of quotes around the argument with spaces and ampersand suffices to send it as one argument to another program:

    %PERL% -w -I%SCRIPTS% "%SCRIPTS"\pre-lock.pl" %1 %2 %3
    

    Since you are just passing arguments to the batch around, there is no need to put more quotes there. Batch arguments retain the quotes. Another way would be:

    %PERL% -w -I%SCRIPTS% "%SCRIPTS"\pre-lock.pl" "%~1" "%~2" "%~3"
    

    which explicitly strips the quotes and then adds them again.

    (Honestly, though, I have no idea how to pass an argument surrounded by quotes to another program so that the program sees "foo" and not foo. But I'm fairly sure that this isn't a problem in this case.)

    In any case, there are a few errors and weirdnesses in your batch file as well:

    1. Try making it a habit of using backslashes instead of forward slashes. cmd uses slashes for command options and therefore built-in commands are rarely happy to see them. The Windows API will happily accept slashes in place of backslashes. The shell isn't so happy about them, though.
    2. The last two lines are doing nohing useful. I guess you wanted

      exit /b %errorlevel%