Skip to content

Commit 38f288e

Browse files
Ilya33zeripath
authored andcommitted
Allow to merge if file path contains " or \ (go-gitea#8629)
* if a filename in a repository contains " or \ the owner can't merge pull request with this files because "git diff-tree" adds double quotes to that filepath example: filepath is ab"cd but "git diff-tree" returns "ab\"cd" now, when the owner click "Merge Pull Request" button the server returns 500 this commit fix it Signed-off-by: Ilya Pavlov <ilux@cpan.org> * add -z option to getDiffTree escape spec symbols for sparse-checkout Signed-off-by: Ilya Pavlov <ilux@cpan.org> * go fmt Signed-off-by: Ilya Pavlov <ilux@cpan.org> * typo Signed-off-by: Ilya Pavlov <ilux@cpan.org> * escape '\' escape all spaces and '!' * use regexp.ReplaceAllString() Signed-off-by: Ilya Pavlov <ilux@cpan.org> * strings.ReplaceAll was added in go 1.12 Signed-off-by: Ilya Pavlov <ilux@cpan.org> * add '\' to regexp.MustCompile Signed-off-by: Ilya Pavlov <ilux@cpan.org>
1 parent 3341aaf commit 38f288e

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

services/pull/merge.go

+24-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"io/ioutil"
1313
"os"
1414
"path/filepath"
15+
"regexp"
1516
"strings"
1617

1718
"code.gitea.io/gitea/models"
@@ -328,16 +329,31 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
328329
return nil
329330
}
330331

332+
var escapedSymbols = regexp.MustCompile(`([*[?! \\])`)
333+
331334
func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) {
332335
getDiffTreeFromBranch := func(repoPath, baseBranch, headBranch string) (string, error) {
333336
var outbuf, errbuf strings.Builder
334337
// Compute the diff-tree for sparse-checkout
335-
if err := git.NewCommand("diff-tree", "--no-commit-id", "--name-only", "-r", "--root", baseBranch, headBranch, "--").RunInDirPipeline(repoPath, &outbuf, &errbuf); err != nil {
338+
if err := git.NewCommand("diff-tree", "--no-commit-id", "--name-only", "-r", "-z", "--root", baseBranch, headBranch, "--").RunInDirPipeline(repoPath, &outbuf, &errbuf); err != nil {
336339
return "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, errbuf.String())
337340
}
338341
return outbuf.String(), nil
339342
}
340343

344+
scanNullTerminatedStrings := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
345+
if atEOF && len(data) == 0 {
346+
return 0, nil, nil
347+
}
348+
if i := bytes.IndexByte(data, '\x00'); i >= 0 {
349+
return i + 1, data[0:i], nil
350+
}
351+
if atEOF {
352+
return len(data), data, nil
353+
}
354+
return 0, nil, nil
355+
}
356+
341357
list, err := getDiffTreeFromBranch(repoPath, baseBranch, headBranch)
342358
if err != nil {
343359
return "", err
@@ -346,8 +362,14 @@ func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) {
346362
// Prefixing '/' for each entry, otherwise all files with the same name in subdirectories would be matched.
347363
out := bytes.Buffer{}
348364
scanner := bufio.NewScanner(strings.NewReader(list))
365+
scanner.Split(scanNullTerminatedStrings)
349366
for scanner.Scan() {
350-
fmt.Fprintf(&out, "/%s\n", scanner.Text())
367+
filepath := scanner.Text()
368+
// escape '*', '?', '[', spaces and '!' prefix
369+
filepath = escapedSymbols.ReplaceAllString(filepath, `\$1`)
370+
// no necessary to escape the first '#' symbol because the first symbol is '/'
371+
fmt.Fprintf(&out, "/%s\n", filepath)
351372
}
373+
352374
return out.String(), nil
353375
}

0 commit comments

Comments
 (0)