github.com/dennwc/btrfs@v0.0.0-20221026161108-3097362dc072/utils.go (about) 1 package btrfs 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 "syscall" 10 "unsafe" 11 12 "github.com/dennwc/btrfs/mtab" 13 ) 14 15 func isBtrfs(path string) (bool, error) { 16 var stfs syscall.Statfs_t 17 if err := syscall.Statfs(path, &stfs); err != nil { 18 return false, &os.PathError{Op: "statfs", Path: path, Err: err} 19 } 20 return int64(stfs.Type) == SuperMagic, nil 21 } 22 23 func findMountRoot(path string) (string, error) { 24 mounts, err := mtab.Mounts() 25 if err != nil { 26 return "", err 27 } 28 longest := "" 29 isBtrfs := false 30 for _, m := range mounts { 31 if !strings.HasPrefix(path, m.Mount) { 32 continue 33 } 34 if len(longest) < len(m.Mount) { 35 longest = m.Mount 36 isBtrfs = m.Type == "btrfs" 37 } 38 } 39 if longest == "" { 40 return "", os.ErrNotExist 41 } else if !isBtrfs { 42 return "", ErrNotBtrfs{Path: longest} 43 } 44 return filepath.Abs(longest) 45 } 46 47 // openDir does the following checks before calling Open: 48 // 1: path is in a btrfs filesystem 49 // 2: path is a directory 50 func openDir(path string) (*os.File, error) { 51 if ok, err := isBtrfs(path); err != nil { 52 return nil, err 53 } else if !ok { 54 return nil, ErrNotBtrfs{Path: path} 55 } 56 file, err := os.Open(path) 57 if err != nil { 58 return nil, err 59 } else if st, err := file.Stat(); err != nil { 60 file.Close() 61 return nil, err 62 } else if !st.IsDir() { 63 file.Close() 64 return nil, fmt.Errorf("not a directory: %s", path) 65 } 66 return file, nil 67 } 68 69 type searchResult struct { 70 TransID uint64 71 ObjectID objectID 72 Type treeKeyType 73 Offset uint64 74 Data []byte 75 } 76 77 func treeSearchRaw(mnt *os.File, key btrfs_ioctl_search_key) (out []searchResult, _ error) { 78 args := btrfs_ioctl_search_args{ 79 key: key, 80 } 81 if err := iocTreeSearch(mnt, &args); err != nil { 82 return nil, err 83 } 84 out = make([]searchResult, 0, args.key.nr_items) 85 buf := args.buf[:] 86 for i := 0; i < int(args.key.nr_items); i++ { 87 h := (*btrfs_ioctl_search_header)(unsafe.Pointer(&buf[0])) 88 buf = buf[unsafe.Sizeof(btrfs_ioctl_search_header{}):] 89 out = append(out, searchResult{ 90 TransID: h.transid, 91 ObjectID: h.objectid, 92 Offset: h.offset, 93 Type: h.typ, 94 Data: buf[:h.len:h.len], // TODO: reallocate? 95 }) 96 buf = buf[h.len:] 97 } 98 return out, nil 99 } 100 101 func stringFromBytes(input []byte) string { 102 if i := bytes.IndexByte(input, 0); i >= 0 { 103 input = input[:i] 104 } 105 return string(input) 106 }