Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/commands/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ only-hash, and progress/status related flags) will change the final hash.
if quiet {
fmt.Fprintf(os.Stdout, "%s\n", output.Hash)
} else {
fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, output.Name)
fmt.Fprintf(os.Stdout, "added %s %s\n", output.Hash, cmdenv.EscNonPrint(output.Name))
}

} else {
Expand Down
27 changes: 27 additions & 0 deletions core/commands/cmdenv/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmdenv

import (
"fmt"
"strconv"
"strings"

"github.com/ipfs/go-ipfs/commands"
Expand Down Expand Up @@ -70,3 +71,29 @@ func GetConfigRoot(env cmds.Environment) (string, error) {

return ctx.ConfigRoot, nil
}

// EscNonPrint converts non-printable characters and backslash into Go escape
// sequences. This is done to display all characters in a string, including
// those that would otherwise not be displayed or have an undesirable effect on
// the display.
func EscNonPrint(s string) string {
if !needEscape(s) {
return s
}

esc := strconv.Quote(s)
// Remove first and last quote, and unescape quotes.
return strings.ReplaceAll(esc[1:len(esc)-1], `\"`, `"`)
}

func needEscape(s string) bool {
if strings.ContainsRune(s, '\\') {
return true
}
for _, r := range s {
if !strconv.IsPrint(r) {
return true
}
}
return false
}
48 changes: 48 additions & 0 deletions core/commands/cmdenv/env_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package cmdenv

import (
"strconv"
"testing"
)

func TestEscNonPrint(t *testing.T) {
b := []byte("hello")
b[2] = 0x7f
s := string(b)
if !needEscape(s) {
t.Fatal("string needs escaping")
}
if !hasNonPrintable(s) {
t.Fatal("expected non-printable")
}
if hasNonPrintable(EscNonPrint(s)) {
t.Fatal("escaped string has non-printable")
}
if EscNonPrint(`hel\lo`) != `hel\\lo` {
t.Fatal("backslash not escaped")
}

s = `hello`
if needEscape(s) {
t.Fatal("string does not need escaping")
}
if EscNonPrint(s) != s {
t.Fatal("string should not have changed")
}
s = `"hello"`
if EscNonPrint(s) != s {
t.Fatal("string should not have changed")
}
if EscNonPrint(`"hel\"lo"`) != `"hel\\"lo"` {
t.Fatal("did not get expected escaped string")
}
}

func hasNonPrintable(s string) bool {
for _, r := range s {
if !strconv.IsPrint(r) {
return true
}
}
return false
}
3 changes: 2 additions & 1 deletion core/commands/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"io"

cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
ncmd "github.com/ipfs/go-ipfs/core/commands/name"
namesys "github.com/ipfs/go-ipfs/namesys"
nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
Expand Down Expand Up @@ -77,7 +78,7 @@ The resolver can recursively resolve:
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *ncmd.ResolvedPath) error {
fmt.Fprintln(w, out.Path.String())
fmt.Fprintln(w, cmdenv.EscNonPrint(out.Path.String()))
return nil
}),
},
Expand Down
8 changes: 4 additions & 4 deletions core/commands/keystore.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,9 +383,9 @@ var keyRenameCmd = &cmds.Command{
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, kro *KeyRenameOutput) error {
if kro.Overwrite {
fmt.Fprintf(w, "Key %s renamed to %s with overwriting\n", kro.Id, kro.Now)
fmt.Fprintf(w, "Key %s renamed to %s with overwriting\n", kro.Id, cmdenv.EscNonPrint(kro.Now))
} else {
fmt.Fprintf(w, "Key %s renamed to %s\n", kro.Id, kro.Now)
fmt.Fprintf(w, "Key %s renamed to %s\n", kro.Id, cmdenv.EscNonPrint(kro.Now))
}
return nil
}),
Expand Down Expand Up @@ -547,9 +547,9 @@ func keyOutputListEncoders() cmds.EncoderFunc {
tw := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
for _, s := range list.Keys {
if withID {
fmt.Fprintf(tw, "%s\t%s\t\n", s.Id, s.Name)
fmt.Fprintf(tw, "%s\t%s\t\n", s.Id, cmdenv.EscNonPrint(s.Name))
} else {
fmt.Fprintf(tw, "%s\n", s.Name)
fmt.Fprintf(tw, "%s\n", cmdenv.EscNonPrint(s.Name))
}
}
tw.Flush()
Expand Down
2 changes: 1 addition & 1 deletion core/commands/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ func tabularOutput(req *cmds.Request, w io.Writer, out *LsOutput, lastObjectHash
}
}

fmt.Fprintf(tw, s, link.Hash, link.Size, link.Name)
fmt.Fprintf(tw, s, link.Hash, link.Size, cmdenv.EscNonPrint(link.Name))
}
}
tw.Flush()
Expand Down
4 changes: 2 additions & 2 deletions core/commands/mount_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ baz
Type: config.Mounts{},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, mounts *config.Mounts) error {
fmt.Fprintf(w, "IPFS mounted at: %s\n", mounts.IPFS)
fmt.Fprintf(w, "IPNS mounted at: %s\n", mounts.IPNS)
fmt.Fprintf(w, "IPFS mounted at: %s\n", cmdenv.EscNonPrint(mounts.IPFS))
fmt.Fprintf(w, "IPNS mounted at: %s\n", cmdenv.EscNonPrint(mounts.IPNS))

return nil
}),
Expand Down
4 changes: 2 additions & 2 deletions core/commands/name/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,9 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
var err error
quieter, _ := req.Options[quieterOptionName].(bool)
if quieter {
_, err = fmt.Fprintln(w, ie.Name)
_, err = fmt.Fprintln(w, cmdenv.EscNonPrint(ie.Name))
} else {
_, err = fmt.Fprintf(w, "Published to %s: %s\n", ie.Name, ie.Value)
_, err = fmt.Fprintf(w, "Published to %s: %s\n", cmdenv.EscNonPrint(ie.Name), cmdenv.EscNonPrint(ie.Value))
}
return err
}),
Expand Down
2 changes: 1 addition & 1 deletion core/commands/object/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ multihash.
fmt.Fprintln(tw, "Hash\tSize\tName")
}
for _, link := range out.Links {
fmt.Fprintf(tw, "%s\t%v\t%s\n", link.Hash, link.Size, link.Name)
fmt.Fprintf(tw, "%s\t%v\t%s\n", link.Hash, link.Size, cmdenv.EscNonPrint(link.Name))
}
tw.Flush()

Expand Down
2 changes: 1 addition & 1 deletion core/commands/pin/remotepin.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ Returns a list of objects that are pinned to a remote pinning service.
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *RemotePinOutput) error {
// pin remote ls produces a flat output similar to legacy pin ls
fmt.Fprintf(w, "%s\t%s\t%s\n", out.Cid, out.Status, out.Name)
fmt.Fprintf(w, "%s\t%s\t%s\n", out.Cid, out.Status, cmdenv.EscNonPrint(out.Name))
return nil
}),
},
Expand Down
2 changes: 1 addition & 1 deletion core/commands/pubsub.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.

func stringListEncoder(req *cmds.Request, w io.Writer, list *stringList) error {
for _, str := range list.Strings {
_, err := fmt.Fprintf(w, "%s\n", str)
_, err := fmt.Fprintf(w, "%s\n", cmdenv.EscNonPrint(str))
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions core/commands/unixfs/ls.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,12 @@ If possible, please use 'ipfs ls' instead.
if len(out.Arguments) > 1 {
for _, arg := range directories[i:] {
if out.Arguments[arg] == hash {
fmt.Fprintf(tw, "%s:\n", arg)
fmt.Fprintf(tw, "%s:\n", cmdenv.EscNonPrint(arg))
}
}
}
for _, link := range object.Links {
fmt.Fprintf(tw, "%s\n", link.Name)
fmt.Fprintf(tw, "%s\n", cmdenv.EscNonPrint(link.Name))
}
}
tw.Flush()
Expand Down
Loading