mirror of
https://github.com/octoleo/restic.git
synced 2024-11-28 07:46:36 +00:00
ls: correctly handle setuid/setgit/sticky bit in ncdu output
This commit is contained in:
parent
a2fe337610
commit
509b339d54
@ -171,7 +171,7 @@ func (p *ncduLsPrinter) Snapshot(sn *restic.Snapshot) {
|
|||||||
fmt.Fprintf(p.out, "[%d, %d, %s", NcduMajorVer, NcduMinorVer, string(snapshotBytes))
|
fmt.Fprintf(p.out, "[%d, %d, %s", NcduMajorVer, NcduMinorVer, string(snapshotBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ncduLsPrinter) Node(path string, node *restic.Node) {
|
func lsNcduNode(path string, node *restic.Node) ([]byte, error) {
|
||||||
type NcduNode struct {
|
type NcduNode struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Asize uint64 `json:"asize"`
|
Asize uint64 `json:"asize"`
|
||||||
@ -196,11 +196,25 @@ func (p *ncduLsPrinter) Node(path string, node *restic.Node) {
|
|||||||
NotReg: node.Type != "dir" && node.Type != "file",
|
NotReg: node.Type != "dir" && node.Type != "file",
|
||||||
Uid: node.UID,
|
Uid: node.UID,
|
||||||
Gid: node.GID,
|
Gid: node.GID,
|
||||||
Mode: uint16(node.Mode),
|
Mode: uint16(node.Mode & os.ModePerm),
|
||||||
Mtime: node.ModTime.Unix(),
|
Mtime: node.ModTime.Unix(),
|
||||||
}
|
}
|
||||||
|
// bits according to inode(7) manpage
|
||||||
|
if node.Mode&os.ModeSetuid != 0 {
|
||||||
|
outNode.Mode |= 0o4000
|
||||||
|
}
|
||||||
|
if node.Mode&os.ModeSetgid != 0 {
|
||||||
|
outNode.Mode |= 0o2000
|
||||||
|
}
|
||||||
|
if node.Mode&os.ModeSticky != 0 {
|
||||||
|
outNode.Mode |= 0o1000
|
||||||
|
}
|
||||||
|
|
||||||
outJson, err := json.Marshal(outNode)
|
return json.Marshal(outNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ncduLsPrinter) Node(path string, node *restic.Node) {
|
||||||
|
outJson, err := lsNcduNode(path, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Warnf("JSON encode failed: %v\n", err)
|
Warnf("JSON encode failed: %v\n", err)
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,12 @@ import (
|
|||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLsNodeJSON(t *testing.T) {
|
type lsTestNode struct {
|
||||||
for _, c := range []struct {
|
|
||||||
path string
|
path string
|
||||||
restic.Node
|
restic.Node
|
||||||
expect string
|
}
|
||||||
}{
|
|
||||||
|
var lsTestNodes []lsTestNode = []lsTestNode{
|
||||||
// Mode is omitted when zero.
|
// Mode is omitted when zero.
|
||||||
// Permissions, by convention is "-" per mode bit
|
// Permissions, by convention is "-" per mode bit
|
||||||
{
|
{
|
||||||
@ -32,7 +32,6 @@ func TestLsNodeJSON(t *testing.T) {
|
|||||||
Group: "nobodies",
|
Group: "nobodies",
|
||||||
Links: 1,
|
Links: 1,
|
||||||
},
|
},
|
||||||
expect: `{"name":"baz","type":"file","path":"/bar/baz","uid":10000000,"gid":20000000,"size":12345,"permissions":"----------","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Even empty files get an explicit size.
|
// Even empty files get an explicit size.
|
||||||
@ -49,7 +48,6 @@ func TestLsNodeJSON(t *testing.T) {
|
|||||||
Group: "not printed",
|
Group: "not printed",
|
||||||
Links: 0xF00,
|
Links: 0xF00,
|
||||||
},
|
},
|
||||||
expect: `{"name":"empty","type":"file","path":"/foo/empty","uid":1001,"gid":1001,"size":0,"permissions":"----------","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Non-regular files do not get a size.
|
// Non-regular files do not get a size.
|
||||||
@ -62,7 +60,6 @@ func TestLsNodeJSON(t *testing.T) {
|
|||||||
Mode: os.ModeSymlink | 0777,
|
Mode: os.ModeSymlink | 0777,
|
||||||
LinkTarget: "not printed",
|
LinkTarget: "not printed",
|
||||||
},
|
},
|
||||||
expect: `{"name":"link","type":"symlink","path":"/foo/link","uid":0,"gid":0,"mode":134218239,"permissions":"Lrwxrwxrwx","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -75,14 +72,33 @@ func TestLsNodeJSON(t *testing.T) {
|
|||||||
AccessTime: time.Date(2021, 2, 3, 4, 5, 6, 7, time.UTC),
|
AccessTime: time.Date(2021, 2, 3, 4, 5, 6, 7, time.UTC),
|
||||||
ChangeTime: time.Date(2022, 3, 4, 5, 6, 7, 8, time.UTC),
|
ChangeTime: time.Date(2022, 3, 4, 5, 6, 7, 8, time.UTC),
|
||||||
},
|
},
|
||||||
expect: `{"name":"directory","type":"dir","path":"/some/directory","uid":0,"gid":0,"mode":2147484141,"permissions":"drwxr-xr-x","mtime":"2020-01-02T03:04:05Z","atime":"2021-02-03T04:05:06.000000007Z","ctime":"2022-03-04T05:06:07.000000008Z","struct_type":"node"}`,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Test encoding of setuid/setgid/sticky bit
|
||||||
|
{
|
||||||
|
path: "/some/sticky",
|
||||||
|
Node: restic.Node{
|
||||||
|
Name: "sticky",
|
||||||
|
Type: "dir",
|
||||||
|
Mode: os.ModeDir | 0755 | os.ModeSetuid | os.ModeSetgid | os.ModeSticky,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLsNodeJSON(t *testing.T) {
|
||||||
|
for i, expect := range []string{
|
||||||
|
`{"name":"baz","type":"file","path":"/bar/baz","uid":10000000,"gid":20000000,"size":12345,"permissions":"----------","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`,
|
||||||
|
`{"name":"empty","type":"file","path":"/foo/empty","uid":1001,"gid":1001,"size":0,"permissions":"----------","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`,
|
||||||
|
`{"name":"link","type":"symlink","path":"/foo/link","uid":0,"gid":0,"mode":134218239,"permissions":"Lrwxrwxrwx","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`,
|
||||||
|
`{"name":"directory","type":"dir","path":"/some/directory","uid":0,"gid":0,"mode":2147484141,"permissions":"drwxr-xr-x","mtime":"2020-01-02T03:04:05Z","atime":"2021-02-03T04:05:06.000000007Z","ctime":"2022-03-04T05:06:07.000000008Z","struct_type":"node"}`,
|
||||||
|
`{"name":"sticky","type":"dir","path":"/some/sticky","uid":0,"gid":0,"mode":2161115629,"permissions":"dugtrwxr-xr-x","mtime":"0001-01-01T00:00:00Z","atime":"0001-01-01T00:00:00Z","ctime":"0001-01-01T00:00:00Z","struct_type":"node"}`,
|
||||||
} {
|
} {
|
||||||
|
c := lsTestNodes[i]
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
enc := json.NewEncoder(buf)
|
enc := json.NewEncoder(buf)
|
||||||
err := lsNodeJSON(enc, c.path, &c.Node)
|
err := lsNodeJSON(enc, c.path, &c.Node)
|
||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
rtest.Equals(t, c.expect+"\n", buf.String())
|
rtest.Equals(t, expect+"\n", buf.String())
|
||||||
|
|
||||||
// Sanity check: output must be valid JSON.
|
// Sanity check: output must be valid JSON.
|
||||||
var v interface{}
|
var v interface{}
|
||||||
@ -90,3 +106,23 @@ func TestLsNodeJSON(t *testing.T) {
|
|||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLsNcduNode(t *testing.T) {
|
||||||
|
for i, expect := range []string{
|
||||||
|
`{"name":"baz","asize":12345,"dsize":12345,"dev":0,"ino":0,"nlink":1,"notreg":false,"uid":10000000,"gid":20000000,"mode":0,"mtime":-62135596800}`,
|
||||||
|
`{"name":"empty","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":3840,"notreg":false,"uid":1001,"gid":1001,"mode":0,"mtime":-62135596800}`,
|
||||||
|
`{"name":"link","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":true,"uid":0,"gid":0,"mode":511,"mtime":-62135596800}`,
|
||||||
|
`{"name":"directory","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":493,"mtime":1577934245}`,
|
||||||
|
`{"name":"sticky","asize":0,"dsize":0,"dev":0,"ino":0,"nlink":0,"notreg":false,"uid":0,"gid":0,"mode":4077,"mtime":-62135596800}`,
|
||||||
|
} {
|
||||||
|
c := lsTestNodes[i]
|
||||||
|
out, err := lsNcduNode(c.path, &c.Node)
|
||||||
|
rtest.OK(t, err)
|
||||||
|
rtest.Equals(t, expect, string(out))
|
||||||
|
|
||||||
|
// Sanity check: output must be valid JSON.
|
||||||
|
var v interface{}
|
||||||
|
err = json.Unmarshal(out, &v)
|
||||||
|
rtest.OK(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user