...
1
2
3
18
19 package fifo
20
21 import (
22 "fmt"
23 "os"
24 "sync"
25 "syscall"
26 )
27
28
29 const O_PATH = 010000000
30
31 type handle struct {
32 f *os.File
33 fd uintptr
34 dev uint64
35 ino uint64
36 closeOnce sync.Once
37 name string
38 }
39
40 func getHandle(fn string) (*handle, error) {
41 f, err := os.OpenFile(fn, O_PATH, 0)
42 if err != nil {
43 return nil, fmt.Errorf("failed to open %v with O_PATH: %w", fn, err)
44 }
45
46 var (
47 stat syscall.Stat_t
48 fd = f.Fd()
49 )
50 if err := syscall.Fstat(int(fd), &stat); err != nil {
51 f.Close()
52 return nil, fmt.Errorf("failed to stat handle %v: %w", fd, err)
53 }
54
55 h := &handle{
56 f: f,
57 name: fn,
58
59 dev: uint64(stat.Dev),
60 ino: stat.Ino,
61 fd: fd,
62 }
63
64
65 if _, err := os.Stat(h.procPath()); err != nil {
66 f.Close()
67 return nil, fmt.Errorf("couldn't stat %v: %w", h.procPath(), err)
68 }
69
70 return h, nil
71 }
72
73 func (h *handle) procPath() string {
74 return fmt.Sprintf("/proc/self/fd/%d", h.fd)
75 }
76
77 func (h *handle) Name() string {
78 return h.name
79 }
80
81 func (h *handle) Path() (string, error) {
82 var stat syscall.Stat_t
83 if err := syscall.Stat(h.procPath(), &stat); err != nil {
84 return "", fmt.Errorf("path %v could not be statted: %w", h.procPath(), err)
85 }
86
87 if uint64(stat.Dev) != h.dev || stat.Ino != h.ino {
88 return "", fmt.Errorf("failed to verify handle %v/%v %v/%v", stat.Dev, h.dev, stat.Ino, h.ino)
89 }
90 return h.procPath(), nil
91 }
92
93 func (h *handle) Close() error {
94 h.closeOnce.Do(func() {
95 h.f.Close()
96 })
97 return nil
98 }
99
View as plain text