tests: reverse: add inode mapping test (TestVirtualFileIno)
Verify that virtual files get assigned inode numbers we expect.
This commit is contained in:
parent
483054efaa
commit
db93a6c54c
@ -201,6 +201,13 @@ func TestTooLongSymlink(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// save later tests the trouble of dealing with ENAMETOOLONG errors
|
||||
defer func() {
|
||||
os.Remove(fn)
|
||||
// immediately create a new symlink so the inode number is not
|
||||
// reused for something else
|
||||
os.Symlink("/tmp", fn)
|
||||
}()
|
||||
t.Logf("Created symlink of length %d", l)
|
||||
_, err = os.Readlink(dirC + "/TooLongSymlink")
|
||||
if err == nil {
|
||||
|
143
tests/reverse/inomap_test.go
Normal file
143
tests/reverse/inomap_test.go
Normal file
@ -0,0 +1,143 @@
|
||||
package reverse_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// findIno looks for the file having inode number `ino` in `dir`.
|
||||
// Returns "" if not found.
|
||||
func findIno(dir string, ino uint64) string {
|
||||
fd, err := os.Open(dir)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
dirents, err := fd.Readdirnames(0)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
fd.Close()
|
||||
for _, entry := range dirents {
|
||||
var st syscall.Stat_t
|
||||
err = syscall.Lstat(dir+"/"+entry, &st)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if ino == st.Ino {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// TestVirtualFileIno creates a directory tree like this:
|
||||
//
|
||||
// TestVirtualFileIno <---- parent
|
||||
// └── xxxxxxx[...] <---- child
|
||||
//
|
||||
// Which looks like this encrypted:
|
||||
//
|
||||
// OLUKdPMg6l87EiKVlufgwIkQL8MD6JdUgOR3a8nEZ-w <---- parent
|
||||
// ├── gocryptfs.diriv <---- diriv
|
||||
// ├── gocryptfs.longname.e31v1ax4h_F0l4jhlN8kCjaWWMq8rO9VVBZ15IYsV50 <---- child
|
||||
// └── gocryptfs.longname.e31v1ax4h_F0l4jhlN8kCjaWWMq8rO9VVBZ15IYsV50.name <---- name
|
||||
//
|
||||
// And verifies that the inode numbers match what we expect.
|
||||
func TestVirtualFileIno(t *testing.T) {
|
||||
if plaintextnames {
|
||||
t.Skip("plaintextnames mode does not have virtual files")
|
||||
}
|
||||
|
||||
type inoTable struct {
|
||||
parent uint64
|
||||
diriv uint64
|
||||
child uint64
|
||||
name uint64
|
||||
}
|
||||
var origInos inoTable
|
||||
var cipherInos inoTable
|
||||
|
||||
parent := dirA + "/TestVirtualFileIno"
|
||||
name := string(bytes.Repeat([]byte("x"), 240))
|
||||
err := os.MkdirAll(parent+"/"+name, 0700)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var st syscall.Stat_t
|
||||
err = syscall.Lstat(parent+"/"+name, &st)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
origInos.child = st.Ino
|
||||
// get inode number of plain parent
|
||||
err = syscall.Lstat(parent, &st)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
origInos.parent = st.Ino
|
||||
// find it in encrypted `dirB`
|
||||
fd, err := os.Open(dirB)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dirents, err := fd.Readdirnames(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fd.Close()
|
||||
encryptedParent := findIno(dirB, origInos.parent)
|
||||
if encryptedParent == "" {
|
||||
t.Fatalf("could not find ino %d in %q", origInos.parent, dirB)
|
||||
}
|
||||
encryptedParent = dirB + "/" + encryptedParent
|
||||
err = syscall.Stat(encryptedParent, &st)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cipherInos.parent = st.Ino
|
||||
fd, err = os.Open(encryptedParent)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dirents, err = fd.Readdirnames(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fd.Close()
|
||||
for _, entry := range dirents {
|
||||
var st2 syscall.Stat_t
|
||||
err = syscall.Lstat(encryptedParent+"/"+entry, &st2)
|
||||
if err != nil {
|
||||
t.Logf("stat %q: %v", entry, err)
|
||||
continue
|
||||
}
|
||||
if entry == "gocryptfs.diriv" {
|
||||
cipherInos.diriv = st2.Ino
|
||||
} else if strings.HasSuffix(entry, ".name") {
|
||||
cipherInos.name = st2.Ino
|
||||
} else {
|
||||
cipherInos.child = st2.Ino
|
||||
}
|
||||
}
|
||||
if origInos.parent != cipherInos.parent {
|
||||
t.Errorf("parent ino mismatch: %d != %d", origInos.parent, cipherInos.parent)
|
||||
}
|
||||
if origInos.parent == cipherInos.diriv {
|
||||
t.Errorf("diriv ino collision: %d == %d", origInos.parent, cipherInos.diriv)
|
||||
}
|
||||
if origInos.parent != cipherInos.diriv-1000000000000000000 {
|
||||
t.Errorf("diriv ino mismatch: %d != %d", origInos.parent, cipherInos.diriv)
|
||||
}
|
||||
if origInos.child != cipherInos.child {
|
||||
t.Errorf("child ino mismatch: %d vs %d", origInos.child, cipherInos.child)
|
||||
}
|
||||
if origInos.child == cipherInos.name {
|
||||
t.Errorf("name ino collision: %d == %d", origInos.child, cipherInos.name)
|
||||
}
|
||||
if origInos.child != cipherInos.name-2000000000000000000 {
|
||||
t.Errorf("name ino mismatch: %d vs %d", origInos.child, cipherInos.name)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user