Skip to content

Commit

Permalink
ui/backup: Quote funny filenames
Browse files Browse the repository at this point in the history
Fixes #2260, #4191.
  • Loading branch information
greatroar committed Feb 11, 2023
1 parent 49fa8fe commit 7f7cbcd
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 8 deletions.
26 changes: 19 additions & 7 deletions internal/ui/termstatus/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
"io"
"os"
"strconv"
"strings"
"unicode"

Expand Down Expand Up @@ -325,6 +326,7 @@ func wideRune(r rune) bool {
}

// SetStatus updates the status lines.
// The lines should not contain newlines; this method adds them.
func (t *Terminal) SetStatus(lines []string) {
if len(lines) == 0 {
return
Expand All @@ -341,21 +343,31 @@ func (t *Terminal) SetStatus(lines []string) {
}
}

// make sure that all lines have a line break and are not too long
// Sanitize lines and truncate them if they're too long.
for i, line := range lines {
line = strings.TrimRight(line, "\n")
line = quote(line)
if width > 0 {
line = Truncate(line, width-2)
}
lines[i] = line + "\n"
if i < len(lines)-1 { // Last line gets no line break.
lines[i] = line + "\n"
}
}

// make sure the last line does not have a line break
last := len(lines) - 1
lines[last] = strings.TrimRight(lines[last], "\n")

select {
case t.status <- status{lines: lines}:
case <-t.closed:
}
}

// Quote lines with funny characters in them, meaning control chars, newlines,
// tabs, anything else non-printable and invalid UTF-8.
func quote(line string) string {
for _, r := range line {
// The replacement character usually means the input is not UTF-8.
if r == unicode.ReplacementChar || !unicode.IsPrint(r) {
return strconv.Quote(line)
}
}
return filename
}
32 changes: 31 additions & 1 deletion internal/ui/termstatus/status_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
package termstatus

import "testing"
import (
"strconv"
"testing"

rtest "github.com/restic/restic/internal/test"
)

func TestQuote(t *testing.T) {
for _, c := range []struct {
in string
needQuote bool
}{
{"foo.bar/baz", false},
{"föó_bàŕ-bãẑ", false},
{" foo ", false},
{"foo bar", false},
{"foo\nbar", true},
{"foo\rbar", true},
{"foo\abar", true},
{"\xff", true},
{`c:\foo\bar`, false},
// Issue #2260: terminal control characters.
{"\x1bm_red_is_beautiful", true},
} {
if c.needQuote {
rtest.Equals(t, strconv.Quote(c.in), quote(c.in))
} else {
rtest.Equals(t, c.in, quote(c.in))
}
}
}

func TestTruncate(t *testing.T) {
var tests = []struct {
Expand Down

0 comments on commit 7f7cbcd

Please sign in to comment.