summaryrefslogtreecommitdiff
path: root/contrib/findholes
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/findholes')
-rw-r--r--contrib/findholes/.gitignore1
-rw-r--r--contrib/findholes/holes/holes.go106
-rw-r--r--contrib/findholes/main.go34
3 files changed, 141 insertions, 0 deletions
diff --git a/contrib/findholes/.gitignore b/contrib/findholes/.gitignore
new file mode 100644
index 0000000..15c37f6
--- /dev/null
+++ b/contrib/findholes/.gitignore
@@ -0,0 +1 @@
+/findholes
diff --git a/contrib/findholes/holes/holes.go b/contrib/findholes/holes/holes.go
new file mode 100644
index 0000000..a2c16de
--- /dev/null
+++ b/contrib/findholes/holes/holes.go
@@ -0,0 +1,106 @@
+// Package holes finds and pretty-prints holes & data sections of a file.
+// Used by TestFileHoleCopy in the gocryptfs test suite.
+package holes
+
+import (
+ "fmt"
+ "syscall"
+)
+
+const (
+ SEEK_DATA = 3
+ SEEK_HOLE = 4
+
+ SegmentHole = SegmentType(100)
+ SegmentData = SegmentType(101)
+ SegmentEOF = SegmentType(102)
+)
+
+type Segment struct {
+ Offset int64
+ Type SegmentType
+}
+
+func (s Segment) String() string {
+ return fmt.Sprintf("%10d %v", s.Offset, s.Type)
+}
+
+type SegmentType int
+
+func (s SegmentType) String() string {
+ switch s {
+ case SegmentHole:
+ return "hole"
+ case SegmentData:
+ return "data"
+ case SegmentEOF:
+ return "eof"
+ default:
+ return "???"
+ }
+}
+
+// PrettyPrint pretty-prints the Segments.
+func PrettyPrint(segments []Segment) (out string) {
+ for _, s := range segments {
+ out += "\n" + s.String()
+ }
+ return out
+}
+
+// Find examines the file passed via file descriptor and returns the found holes
+// and data sections.
+func Find(fd int) (segments []Segment, err error) {
+ var st syscall.Stat_t
+ err = syscall.Fstat(fd, &st)
+ if err != nil {
+ return nil, err
+ }
+ totalSize := st.Size
+
+ var cursor int64
+
+ // find out if file starts with data or hole
+ off, err := syscall.Seek(fd, 0, SEEK_DATA)
+ if err == syscall.ENXIO {
+ segments = append(segments,
+ Segment{0, SegmentHole},
+ Segment{totalSize, SegmentEOF})
+ return segments, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ if off == cursor {
+ segments = append(segments, Segment{0, SegmentData})
+ } else {
+ segments = append(segments,
+ Segment{0, SegmentHole},
+ Segment{totalSize, SegmentData})
+ cursor = off
+ }
+
+ // now we are at the start of data.
+ // find next hole, then next data, then next hole, then next data...
+ for {
+ cursor, err = syscall.Seek(fd, cursor, SEEK_HOLE)
+ if err != nil {
+ return nil, err
+ }
+ if cursor == totalSize {
+ segments = append(segments, Segment{cursor, SegmentEOF})
+ break
+ }
+ segments = append(segments, Segment{cursor, SegmentHole})
+ cursor, err = syscall.Seek(fd, cursor, SEEK_DATA)
+ if err != nil {
+ return nil, err
+ }
+ if cursor == totalSize {
+ segments = append(segments, Segment{cursor, SegmentEOF})
+ break
+ }
+ segments = append(segments, Segment{cursor, SegmentData})
+ }
+ return segments, nil
+}
diff --git a/contrib/findholes/main.go b/contrib/findholes/main.go
new file mode 100644
index 0000000..6f1ae64
--- /dev/null
+++ b/contrib/findholes/main.go
@@ -0,0 +1,34 @@
+// Find and pretty-print holes & data sections of a file.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+
+ "github.com/rfjakob/gocryptfs/contrib/findholes/holes"
+)
+
+func main() {
+ flag.Parse()
+ if flag.NArg() != 1 {
+ fmt.Printf("Usage: findholes FILE\n")
+ os.Exit(1)
+ }
+
+ f, err := os.Open(flag.Arg(0))
+ if err != nil {
+ // os.Open() gives nicer error messages than syscall.Open()
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ defer f.Close()
+
+ segments, err := holes.Find(int(f.Fd()))
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ fmt.Println(holes.PrettyPrint(segments))
+}