16 "fmt" |
16 "fmt" |
17 "runtime" |
17 "runtime" |
18 "syscall" |
18 "syscall" |
19 "unsafe" |
19 "unsafe" |
20 ) |
20 ) |
|
21 |
|
22 //sys closedir(dir uintptr) (err error) |
|
23 //sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) |
|
24 |
|
25 func fdopendir(fd int) (dir uintptr, err error) { |
|
26 r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0) |
|
27 dir = uintptr(r0) |
|
28 if e1 != 0 { |
|
29 err = errnoErr(e1) |
|
30 } |
|
31 return |
|
32 } |
|
33 |
|
34 var libc_fdopendir_trampoline_addr uintptr |
|
35 |
|
36 //go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib" |
|
37 |
|
38 func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) { |
|
39 // Simulate Getdirentries using fdopendir/readdir_r/closedir. |
|
40 // We store the number of entries to skip in the seek |
|
41 // offset of fd. See issue #31368. |
|
42 // It's not the full required semantics, but should handle the case |
|
43 // of calling Getdirentries or ReadDirent repeatedly. |
|
44 // It won't handle assigning the results of lseek to *basep, or handle |
|
45 // the directory being edited underfoot. |
|
46 skip, err := Seek(fd, 0, 1 /* SEEK_CUR */) |
|
47 if err != nil { |
|
48 return 0, err |
|
49 } |
|
50 |
|
51 // We need to duplicate the incoming file descriptor |
|
52 // because the caller expects to retain control of it, but |
|
53 // fdopendir expects to take control of its argument. |
|
54 // Just Dup'ing the file descriptor is not enough, as the |
|
55 // result shares underlying state. Use Openat to make a really |
|
56 // new file descriptor referring to the same directory. |
|
57 fd2, err := Openat(fd, ".", O_RDONLY, 0) |
|
58 if err != nil { |
|
59 return 0, err |
|
60 } |
|
61 d, err := fdopendir(fd2) |
|
62 if err != nil { |
|
63 Close(fd2) |
|
64 return 0, err |
|
65 } |
|
66 defer closedir(d) |
|
67 |
|
68 var cnt int64 |
|
69 for { |
|
70 var entry Dirent |
|
71 var entryp *Dirent |
|
72 e := readdir_r(d, &entry, &entryp) |
|
73 if e != 0 { |
|
74 return n, errnoErr(e) |
|
75 } |
|
76 if entryp == nil { |
|
77 break |
|
78 } |
|
79 if skip > 0 { |
|
80 skip-- |
|
81 cnt++ |
|
82 continue |
|
83 } |
|
84 |
|
85 reclen := int(entry.Reclen) |
|
86 if reclen > len(buf) { |
|
87 // Not enough room. Return for now. |
|
88 // The counter will let us know where we should start up again. |
|
89 // Note: this strategy for suspending in the middle and |
|
90 // restarting is O(n^2) in the length of the directory. Oh well. |
|
91 break |
|
92 } |
|
93 |
|
94 // Copy entry into return buffer. |
|
95 s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen) |
|
96 copy(buf, s) |
|
97 |
|
98 buf = buf[reclen:] |
|
99 n += reclen |
|
100 cnt++ |
|
101 } |
|
102 // Set the seek offset of the input fd to record |
|
103 // how many files we've already returned. |
|
104 _, err = Seek(fd, cnt, 0 /* SEEK_SET */) |
|
105 if err != nil { |
|
106 return n, err |
|
107 } |
|
108 |
|
109 return n, nil |
|
110 } |
21 |
111 |
22 // SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. |
112 // SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets. |
23 type SockaddrDatalink struct { |
113 type SockaddrDatalink struct { |
24 Len uint8 |
114 Len uint8 |
25 Family uint8 |
115 Family uint8 |