[ Debian Janitor ]
New upstream snapshot.
Debian Janitor
1 year, 6 months ago
0 | linters: | |
1 | enable: | |
2 | - staticcheck | |
3 | - unconvert | |
4 | - gofmt | |
5 | - goimports | |
6 | - golint | |
7 | - ineffassign | |
8 | - vet | |
9 | - unused | |
10 | - misspell | |
11 | disable: | |
12 | - errcheck | |
13 | ||
14 | run: | |
15 | timeout: 3m | |
16 | skip-dirs: | |
17 | - vendor |
0 | MIT | |
1 | ||
2 | Copyright (C) 2016 Tõnis Tiigi <tonistiigi@gmail.com> | |
3 | ||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 | of this software and associated documentation files (the "Software"), to deal | |
6 | in the Software without restriction, including without limitation the rights | |
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 | copies of the Software, and to permit persons to whom the Software is | |
9 | furnished to do so, subject to the following conditions: | |
10 | ||
11 | The above copyright notice and this permission notice shall be included in | |
12 | all copies or substantial portions of the Software. | |
13 | ||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 | THE SOFTWARE.⏎ | |
0 | Apache License | |
1 | Version 2.0, January 2004 | |
2 | http://www.apache.org/licenses/ | |
3 | ||
4 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |
5 | ||
6 | 1. Definitions. | |
7 | ||
8 | "License" shall mean the terms and conditions for use, reproduction, | |
9 | and distribution as defined by Sections 1 through 9 of this document. | |
10 | ||
11 | "Licensor" shall mean the copyright owner or entity authorized by | |
12 | the copyright owner that is granting the License. | |
13 | ||
14 | "Legal Entity" shall mean the union of the acting entity and all | |
15 | other entities that control, are controlled by, or are under common | |
16 | control with that entity. For the purposes of this definition, | |
17 | "control" means (i) the power, direct or indirect, to cause the | |
18 | direction or management of such entity, whether by contract or | |
19 | otherwise, or (ii) ownership of fifty percent (50%) or more of the | |
20 | outstanding shares, or (iii) beneficial ownership of such entity. | |
21 | ||
22 | "You" (or "Your") shall mean an individual or Legal Entity | |
23 | exercising permissions granted by this License. | |
24 | ||
25 | "Source" form shall mean the preferred form for making modifications, | |
26 | including but not limited to software source code, documentation | |
27 | source, and configuration files. | |
28 | ||
29 | "Object" form shall mean any form resulting from mechanical | |
30 | transformation or translation of a Source form, including but | |
31 | not limited to compiled object code, generated documentation, | |
32 | and conversions to other media types. | |
33 | ||
34 | "Work" shall mean the work of authorship, whether in Source or | |
35 | Object form, made available under the License, as indicated by a | |
36 | copyright notice that is included in or attached to the work | |
37 | (an example is provided in the Appendix below). | |
38 | ||
39 | "Derivative Works" shall mean any work, whether in Source or Object | |
40 | form, that is based on (or derived from) the Work and for which the | |
41 | editorial revisions, annotations, elaborations, or other modifications | |
42 | represent, as a whole, an original work of authorship. For the purposes | |
43 | of this License, Derivative Works shall not include works that remain | |
44 | separable from, or merely link (or bind by name) to the interfaces of, | |
45 | the Work and Derivative Works thereof. | |
46 | ||
47 | "Contribution" shall mean any work of authorship, including | |
48 | the original version of the Work and any modifications or additions | |
49 | to that Work or Derivative Works thereof, that is intentionally | |
50 | submitted to Licensor for inclusion in the Work by the copyright owner | |
51 | or by an individual or Legal Entity authorized to submit on behalf of | |
52 | the copyright owner. For the purposes of this definition, "submitted" | |
53 | means any form of electronic, verbal, or written communication sent | |
54 | to the Licensor or its representatives, including but not limited to | |
55 | communication on electronic mailing lists, source code control systems, | |
56 | and issue tracking systems that are managed by, or on behalf of, the | |
57 | Licensor for the purpose of discussing and improving the Work, but | |
58 | excluding communication that is conspicuously marked or otherwise | |
59 | designated in writing by the copyright owner as "Not a Contribution." | |
60 | ||
61 | "Contributor" shall mean Licensor and any individual or Legal Entity | |
62 | on behalf of whom a Contribution has been received by Licensor and | |
63 | subsequently incorporated within the Work. | |
64 | ||
65 | 2. Grant of Copyright License. Subject to the terms and conditions of | |
66 | this License, each Contributor hereby grants to You a perpetual, | |
67 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
68 | copyright license to reproduce, prepare Derivative Works of, | |
69 | publicly display, publicly perform, sublicense, and distribute the | |
70 | Work and such Derivative Works in Source or Object form. | |
71 | ||
72 | 3. Grant of Patent License. Subject to the terms and conditions of | |
73 | this License, each Contributor hereby grants to You a perpetual, | |
74 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
75 | (except as stated in this section) patent license to make, have made, | |
76 | use, offer to sell, sell, import, and otherwise transfer the Work, | |
77 | where such license applies only to those patent claims licensable | |
78 | by such Contributor that are necessarily infringed by their | |
79 | Contribution(s) alone or by combination of their Contribution(s) | |
80 | with the Work to which such Contribution(s) was submitted. If You | |
81 | institute patent litigation against any entity (including a | |
82 | cross-claim or counterclaim in a lawsuit) alleging that the Work | |
83 | or a Contribution incorporated within the Work constitutes direct | |
84 | or contributory patent infringement, then any patent licenses | |
85 | granted to You under this License for that Work shall terminate | |
86 | as of the date such litigation is filed. | |
87 | ||
88 | 4. Redistribution. You may reproduce and distribute copies of the | |
89 | Work or Derivative Works thereof in any medium, with or without | |
90 | modifications, and in Source or Object form, provided that You | |
91 | meet the following conditions: | |
92 | ||
93 | (a) You must give any other recipients of the Work or | |
94 | Derivative Works a copy of this License; and | |
95 | ||
96 | (b) You must cause any modified files to carry prominent notices | |
97 | stating that You changed the files; and | |
98 | ||
99 | (c) You must retain, in the Source form of any Derivative Works | |
100 | that You distribute, all copyright, patent, trademark, and | |
101 | attribution notices from the Source form of the Work, | |
102 | excluding those notices that do not pertain to any part of | |
103 | the Derivative Works; and | |
104 | ||
105 | (d) If the Work includes a "NOTICE" text file as part of its | |
106 | distribution, then any Derivative Works that You distribute must | |
107 | include a readable copy of the attribution notices contained | |
108 | within such NOTICE file, excluding those notices that do not | |
109 | pertain to any part of the Derivative Works, in at least one | |
110 | of the following places: within a NOTICE text file distributed | |
111 | as part of the Derivative Works; within the Source form or | |
112 | documentation, if provided along with the Derivative Works; or, | |
113 | within a display generated by the Derivative Works, if and | |
114 | wherever such third-party notices normally appear. The contents | |
115 | of the NOTICE file are for informational purposes only and | |
116 | do not modify the License. You may add Your own attribution | |
117 | notices within Derivative Works that You distribute, alongside | |
118 | or as an addendum to the NOTICE text from the Work, provided | |
119 | that such additional attribution notices cannot be construed | |
120 | as modifying the License. | |
121 | ||
122 | You may add Your own copyright statement to Your modifications and | |
123 | may provide additional or different license terms and conditions | |
124 | for use, reproduction, or distribution of Your modifications, or | |
125 | for any such Derivative Works as a whole, provided Your use, | |
126 | reproduction, and distribution of the Work otherwise complies with | |
127 | the conditions stated in this License. | |
128 | ||
129 | 5. Submission of Contributions. Unless You explicitly state otherwise, | |
130 | any Contribution intentionally submitted for inclusion in the Work | |
131 | by You to the Licensor shall be under the terms and conditions of | |
132 | this License, without any additional terms or conditions. | |
133 | Notwithstanding the above, nothing herein shall supersede or modify | |
134 | the terms of any separate license agreement you may have executed | |
135 | with Licensor regarding such Contributions. | |
136 | ||
137 | 6. Trademarks. This License does not grant permission to use the trade | |
138 | names, trademarks, service marks, or product names of the Licensor, | |
139 | except as required for reasonable and customary use in describing the | |
140 | origin of the Work and reproducing the content of the NOTICE file. | |
141 | ||
142 | 7. Disclaimer of Warranty. Unless required by applicable law or | |
143 | agreed to in writing, Licensor provides the Work (and each | |
144 | Contributor provides its Contributions) on an "AS IS" BASIS, | |
145 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
146 | implied, including, without limitation, any warranties or conditions | |
147 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |
148 | PARTICULAR PURPOSE. You are solely responsible for determining the | |
149 | appropriateness of using or redistributing the Work and assume any | |
150 | risks associated with Your exercise of permissions under this License. | |
151 | ||
152 | 8. Limitation of Liability. In no event and under no legal theory, | |
153 | whether in tort (including negligence), contract, or otherwise, | |
154 | unless required by applicable law (such as deliberate and grossly | |
155 | negligent acts) or agreed to in writing, shall any Contributor be | |
156 | liable to You for damages, including any direct, indirect, special, | |
157 | incidental, or consequential damages of any character arising as a | |
158 | result of this License or out of the use or inability to use the | |
159 | Work (including but not limited to damages for loss of goodwill, | |
160 | work stoppage, computer failure or malfunction, or any and all | |
161 | other commercial damages or losses), even if such Contributor | |
162 | has been advised of the possibility of such damages. | |
163 | ||
164 | 9. Accepting Warranty or Additional Liability. While redistributing | |
165 | the Work or Derivative Works thereof, You may choose to offer, | |
166 | and charge a fee for, acceptance of support, warranty, indemnity, | |
167 | or other liability obligations and/or rights consistent with this | |
168 | License. However, in accepting such obligations, You may act only | |
169 | on Your own behalf and on Your sole responsibility, not on behalf | |
170 | of any other Contributor, and only if You agree to indemnify, | |
171 | defend, and hold each Contributor harmless for any liability | |
172 | incurred by, or claims asserted against, such Contributor by reason | |
173 | of your accepting any such warranty or additional liability. | |
174 | ||
175 | END OF TERMS AND CONDITIONS | |
176 | ||
177 | APPENDIX: How to apply the Apache License to your work. | |
178 | ||
179 | To apply the Apache License to your work, attach the following | |
180 | boilerplate notice, with the fields enclosed by brackets "[]" | |
181 | replaced with your own identifying information. (Don't include | |
182 | the brackets!) The text should be enclosed in the appropriate | |
183 | comment syntax for the file format. We also recommend that a | |
184 | file or class name and description of purpose be included on the | |
185 | same "printed page" as the copyright notice for easier | |
186 | identification within third-party archives. | |
187 | ||
188 | Copyright [yyyy] [name of copyright owner] | |
189 | ||
190 | Licensed under the Apache License, Version 2.0 (the "License"); | |
191 | you may not use this file except in compliance with the License. | |
192 | You may obtain a copy of the License at | |
193 | ||
194 | http://www.apache.org/licenses/LICENSE-2.0 | |
195 | ||
196 | Unless required by applicable law or agreed to in writing, software | |
197 | distributed under the License is distributed on an "AS IS" BASIS, | |
198 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
199 | See the License for the specific language governing permissions and | |
200 | limitations under the License. |
0 | .PHONY: fmt vet test deps | |
0 | # Copyright The containerd Authors. | |
1 | ||
2 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
3 | # you may not use this file except in compliance with the License. | |
4 | # You may obtain a copy of the License at | |
5 | ||
6 | # http://www.apache.org/licenses/LICENSE-2.0 | |
7 | ||
8 | # Unless required by applicable law or agreed to in writing, software | |
9 | # distributed under the License is distributed on an "AS IS" BASIS, | |
10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
11 | # See the License for the specific language governing permissions and | |
12 | # limitations under the License. | |
13 | ||
14 | .PHONY: check test deps | |
1 | 15 | |
2 | 16 | test: deps |
3 | go test -v ./... | |
17 | go test -v -race ./... | |
4 | 18 | |
5 | 19 | deps: |
6 | go get -d -t ./... | |
20 | go mod vendor | |
7 | 21 | |
8 | fmt: | |
9 | gofmt -s -l . | |
10 | ||
11 | vet: | |
12 | go vet ./... | |
22 | check: | |
23 | GOGC=75 golangci-lint run |
0 | golang-github-tonistiigi-fifo (0.0~git20161203.0.fe870cc-2) UNRELEASED; urgency=medium | |
0 | golang-github-tonistiigi-fifo (1.0.0+git20221027.1.d1f554c-1) UNRELEASED; urgency=medium | |
1 | 1 | |
2 | 2 | [ Alexandre Viau ] |
3 | 3 | * Point Vcs-* urls to salsa.debian.org. |
5 | 5 | [ Jelmer Vernooij ] |
6 | 6 | * Change priority extra to priority optional. |
7 | 7 | |
8 | -- Alexandre Viau <aviau@debian.org> Mon, 02 Apr 2018 21:01:31 -0400 | |
8 | [ Debian Janitor ] | |
9 | * New upstream snapshot. | |
10 | ||
11 | -- Alexandre Viau <aviau@debian.org> Wed, 09 Nov 2022 23:03:56 -0000 | |
9 | 12 | |
10 | 13 | golang-github-tonistiigi-fifo (0.0~git20161203.0.fe870cc-1) unstable; urgency=medium |
11 | 14 |
0 | /* | |
1 | Copyright The containerd Authors. | |
2 | ||
3 | Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | you may not use this file except in compliance with the License. | |
5 | You may obtain a copy of the License at | |
6 | ||
7 | http://www.apache.org/licenses/LICENSE-2.0 | |
8 | ||
9 | Unless required by applicable law or agreed to in writing, software | |
10 | distributed under the License is distributed on an "AS IS" BASIS, | |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | See the License for the specific language governing permissions and | |
13 | limitations under the License. | |
14 | */ | |
15 | ||
16 | package fifo | |
17 | ||
18 | import "errors" | |
19 | ||
20 | var ( | |
21 | ErrClosed = errors.New("fifo closed") | |
22 | ErrCtrlClosed = errors.New("control of closed fifo") | |
23 | ErrRdFrmWRONLY = errors.New("reading from write-only fifo") | |
24 | ErrReadClosed = errors.New("reading from a closed fifo") | |
25 | ErrWrToRDONLY = errors.New("writing to read-only fifo") | |
26 | ErrWriteClosed = errors.New("writing to a closed fifo") | |
27 | ) |
0 | //go:build !windows | |
1 | // +build !windows | |
2 | ||
3 | /* | |
4 | Copyright The containerd Authors. | |
5 | ||
6 | Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | you may not use this file except in compliance with the License. | |
8 | You may obtain a copy of the License at | |
9 | ||
10 | http://www.apache.org/licenses/LICENSE-2.0 | |
11 | ||
12 | Unless required by applicable law or agreed to in writing, software | |
13 | distributed under the License is distributed on an "AS IS" BASIS, | |
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | See the License for the specific language governing permissions and | |
16 | limitations under the License. | |
17 | */ | |
18 | ||
0 | 19 | package fifo |
1 | 20 | |
2 | 21 | import ( |
22 | "context" | |
23 | "fmt" | |
3 | 24 | "io" |
4 | 25 | "os" |
5 | 26 | "runtime" |
6 | 27 | "sync" |
7 | 28 | "syscall" |
8 | 29 | |
9 | "github.com/pkg/errors" | |
10 | "golang.org/x/net/context" | |
30 | "golang.org/x/sys/unix" | |
11 | 31 | ) |
12 | 32 | |
13 | 33 | type fifo struct { |
24 | 44 | |
25 | 45 | var leakCheckWg *sync.WaitGroup |
26 | 46 | |
47 | // OpenFifoDup2 is same as OpenFifo, but additionally creates a copy of the FIFO file descriptor with dup2 syscall. | |
48 | func OpenFifoDup2(ctx context.Context, fn string, flag int, perm os.FileMode, fd int) (io.ReadWriteCloser, error) { | |
49 | f, err := openFifo(ctx, fn, flag, perm) | |
50 | if err != nil { | |
51 | return nil, fmt.Errorf("fifo error: %w", err) | |
52 | } | |
53 | ||
54 | if err := unix.Dup2(int(f.file.Fd()), fd); err != nil { | |
55 | _ = f.Close() | |
56 | return nil, fmt.Errorf("dup2 error: %w", err) | |
57 | } | |
58 | ||
59 | return f, nil | |
60 | } | |
61 | ||
27 | 62 | // OpenFifo opens a fifo. Returns io.ReadWriteCloser. |
28 | 63 | // Context can be used to cancel this function until open(2) has not returned. |
29 | 64 | // Accepted flags: |
30 | // - syscall.O_CREAT - create new fifo if one doesn't exist | |
31 | // - syscall.O_RDONLY - open fifo only from reader side | |
32 | // - syscall.O_WRONLY - open fifo only from writer side | |
33 | // - syscall.O_RDWR - open fifo from both sides, never block on syscall level | |
34 | // - syscall.O_NONBLOCK - return io.ReadWriteCloser even if other side of the | |
65 | // - syscall.O_CREAT - create new fifo if one doesn't exist | |
66 | // - syscall.O_RDONLY - open fifo only from reader side | |
67 | // - syscall.O_WRONLY - open fifo only from writer side | |
68 | // - syscall.O_RDWR - open fifo from both sides, never block on syscall level | |
69 | // - syscall.O_NONBLOCK - return io.ReadWriteCloser even if other side of the | |
35 | 70 | // fifo isn't open. read/write will be connected after the actual fifo is |
36 | 71 | // open or after fifo is closed. |
37 | 72 | func OpenFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) { |
73 | return openFifo(ctx, fn, flag, perm) | |
74 | } | |
75 | ||
76 | func openFifo(ctx context.Context, fn string, flag int, perm os.FileMode) (*fifo, error) { | |
38 | 77 | if _, err := os.Stat(fn); err != nil { |
39 | 78 | if os.IsNotExist(err) && flag&syscall.O_CREAT != 0 { |
40 | if err := mkfifo(fn, uint32(perm&os.ModePerm)); err != nil && !os.IsExist(err) { | |
41 | return nil, errors.Wrapf(err, "error creating fifo %v", fn) | |
79 | if err := syscall.Mkfifo(fn, uint32(perm&os.ModePerm)); err != nil && !os.IsExist(err) { | |
80 | return nil, fmt.Errorf("error creating fifo %v: %w", fn, err) | |
42 | 81 | } |
43 | 82 | } else { |
44 | 83 | return nil, err |
74 | 113 | } |
75 | 114 | select { |
76 | 115 | case <-ctx.Done(): |
77 | f.Close() | |
116 | select { | |
117 | case <-f.opened: | |
118 | default: | |
119 | f.Close() | |
120 | } | |
78 | 121 | case <-f.opened: |
79 | 122 | case <-f.closed: |
80 | 123 | } |
95 | 138 | case <-ctx.Done(): |
96 | 139 | err = ctx.Err() |
97 | 140 | default: |
98 | err = errors.Errorf("fifo %v was closed before opening", h.Name()) | |
141 | err = fmt.Errorf("fifo %v was closed before opening", h.Name()) | |
99 | 142 | } |
100 | 143 | if file != nil { |
101 | 144 | file.Close() |
126 | 169 | // Read from a fifo to a byte array. |
127 | 170 | func (f *fifo) Read(b []byte) (int, error) { |
128 | 171 | if f.flag&syscall.O_WRONLY > 0 { |
129 | return 0, errors.New("reading from write-only fifo") | |
172 | return 0, ErrRdFrmWRONLY | |
130 | 173 | } |
131 | 174 | select { |
132 | 175 | case <-f.opened: |
137 | 180 | case <-f.opened: |
138 | 181 | return f.file.Read(b) |
139 | 182 | case <-f.closed: |
140 | return 0, errors.New("reading from a closed fifo") | |
183 | return 0, ErrReadClosed | |
141 | 184 | } |
142 | 185 | } |
143 | 186 | |
144 | 187 | // Write from byte array to a fifo. |
145 | 188 | func (f *fifo) Write(b []byte) (int, error) { |
146 | 189 | if f.flag&(syscall.O_WRONLY|syscall.O_RDWR) == 0 { |
147 | return 0, errors.New("writing to read-only fifo") | |
190 | return 0, ErrWrToRDONLY | |
148 | 191 | } |
149 | 192 | select { |
150 | 193 | case <-f.opened: |
155 | 198 | case <-f.opened: |
156 | 199 | return f.file.Write(b) |
157 | 200 | case <-f.closed: |
158 | return 0, errors.New("writing to a closed fifo") | |
201 | return 0, ErrWriteClosed | |
159 | 202 | } |
160 | 203 | } |
161 | 204 | |
163 | 206 | // before open(2) has returned and fifo was never opened. |
164 | 207 | func (f *fifo) Close() (retErr error) { |
165 | 208 | for { |
209 | if f == nil { | |
210 | return | |
211 | } | |
212 | ||
166 | 213 | select { |
167 | 214 | case <-f.closed: |
168 | 215 | f.handle.Close() |
0 | //go:build linux | |
0 | 1 | // +build linux |
2 | ||
3 | /* | |
4 | Copyright The containerd Authors. | |
5 | ||
6 | Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | you may not use this file except in compliance with the License. | |
8 | You may obtain a copy of the License at | |
9 | ||
10 | http://www.apache.org/licenses/LICENSE-2.0 | |
11 | ||
12 | Unless required by applicable law or agreed to in writing, software | |
13 | distributed under the License is distributed on an "AS IS" BASIS, | |
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | See the License for the specific language governing permissions and | |
16 | limitations under the License. | |
17 | */ | |
1 | 18 | |
2 | 19 | package fifo |
3 | 20 | |
4 | 21 | import ( |
5 | "io/ioutil" | |
22 | "context" | |
6 | 23 | "os" |
7 | 24 | "path/filepath" |
8 | 25 | "sync" |
11 | 28 | "time" |
12 | 29 | |
13 | 30 | "github.com/stretchr/testify/assert" |
14 | "golang.org/x/net/context" | |
15 | 31 | ) |
16 | 32 | |
17 | 33 | func TestFifoCloseAfterRm(t *testing.T) { |
18 | tmpdir, err := ioutil.TempDir("", "fifos") | |
34 | tmpdir, err := os.MkdirTemp("", "fifos") | |
19 | 35 | assert.NoError(t, err) |
20 | 36 | defer os.RemoveAll(tmpdir) |
21 | 37 |
0 | // +build !linux | |
0 | //go:build !linux && !windows | |
1 | // +build !linux,!windows | |
2 | ||
3 | /* | |
4 | Copyright The containerd Authors. | |
5 | ||
6 | Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | you may not use this file except in compliance with the License. | |
8 | You may obtain a copy of the License at | |
9 | ||
10 | http://www.apache.org/licenses/LICENSE-2.0 | |
11 | ||
12 | Unless required by applicable law or agreed to in writing, software | |
13 | distributed under the License is distributed on an "AS IS" BASIS, | |
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | See the License for the specific language governing permissions and | |
16 | limitations under the License. | |
17 | */ | |
1 | 18 | |
2 | 19 | package fifo |
3 | 20 | |
4 | 21 | import ( |
5 | "io/ioutil" | |
22 | "context" | |
6 | 23 | "os" |
7 | 24 | "path/filepath" |
8 | 25 | "syscall" |
10 | 27 | "time" |
11 | 28 | |
12 | 29 | "github.com/stretchr/testify/assert" |
13 | "golang.org/x/net/context" | |
14 | 30 | ) |
15 | 31 | |
16 | 32 | func TestFifoCloseAfterRm(t *testing.T) { |
17 | tmpdir, err := ioutil.TempDir("", "fifos") | |
33 | tmpdir, err := os.MkdirTemp("", "fifos") | |
18 | 34 | assert.NoError(t, err) |
19 | 35 | defer os.RemoveAll(tmpdir) |
20 | 36 |
0 | //go:build !windows | |
1 | // +build !windows | |
2 | ||
3 | /* | |
4 | Copyright The containerd Authors. | |
5 | ||
6 | Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | you may not use this file except in compliance with the License. | |
8 | You may obtain a copy of the License at | |
9 | ||
10 | http://www.apache.org/licenses/LICENSE-2.0 | |
11 | ||
12 | Unless required by applicable law or agreed to in writing, software | |
13 | distributed under the License is distributed on an "AS IS" BASIS, | |
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | See the License for the specific language governing permissions and | |
16 | limitations under the License. | |
17 | */ | |
18 | ||
0 | 19 | package fifo |
1 | 20 | |
2 | 21 | import ( |
22 | "context" | |
3 | 23 | "io" |
4 | "io/ioutil" | |
5 | 24 | "os" |
6 | 25 | "path/filepath" |
7 | 26 | "sync" |
10 | 29 | "time" |
11 | 30 | |
12 | 31 | "github.com/stretchr/testify/assert" |
13 | "golang.org/x/net/context" | |
14 | 32 | ) |
15 | 33 | |
16 | 34 | func TestFifoCancel(t *testing.T) { |
17 | tmpdir, err := ioutil.TempDir("", "fifos") | |
35 | tmpdir, err := os.MkdirTemp("", "fifos") | |
18 | 36 | assert.NoError(t, err) |
19 | 37 | defer os.RemoveAll(tmpdir) |
20 | 38 | |
37 | 55 | b := make([]byte, 32) |
38 | 56 | n, err := f.Read(b) |
39 | 57 | assert.Equal(t, n, 0) |
40 | assert.EqualError(t, err, "reading from a closed fifo") | |
58 | assert.Equal(t, err, ErrReadClosed) | |
41 | 59 | |
42 | 60 | select { |
43 | 61 | case <-ctx.Done(): |
48 | 66 | } |
49 | 67 | |
50 | 68 | func TestFifoReadWrite(t *testing.T) { |
51 | tmpdir, err := ioutil.TempDir("", "fifos") | |
69 | tmpdir, err := os.MkdirTemp("", "fifos") | |
52 | 70 | assert.NoError(t, err) |
53 | 71 | defer os.RemoveAll(tmpdir) |
54 | 72 | |
126 | 144 | } |
127 | 145 | |
128 | 146 | func TestFifoCancelOneSide(t *testing.T) { |
129 | tmpdir, err := ioutil.TempDir("", "fifos") | |
147 | tmpdir, err := os.MkdirTemp("", "fifos") | |
130 | 148 | assert.NoError(t, err) |
131 | 149 | defer os.RemoveAll(tmpdir) |
132 | 150 | |
163 | 181 | t.Fatal("read should have unblocked") |
164 | 182 | } |
165 | 183 | |
166 | assert.EqualError(t, err, "reading from a closed fifo") | |
184 | assert.Equal(t, err, ErrReadClosed) | |
167 | 185 | |
168 | 186 | assert.NoError(t, checkWgDone(leakCheckWg)) |
169 | 187 | } |
170 | 188 | |
171 | 189 | func TestFifoBlocking(t *testing.T) { |
172 | tmpdir, err := ioutil.TempDir("", "fifos") | |
190 | tmpdir, err := os.MkdirTemp("", "fifos") | |
173 | 191 | assert.NoError(t, err) |
174 | 192 | defer os.RemoveAll(tmpdir) |
175 | 193 | |
236 | 254 | } |
237 | 255 | |
238 | 256 | func TestFifoORDWR(t *testing.T) { |
239 | tmpdir, err := ioutil.TempDir("", "fifos") | |
257 | tmpdir, err := os.MkdirTemp("", "fifos") | |
240 | 258 | assert.NoError(t, err) |
241 | 259 | defer os.RemoveAll(tmpdir) |
242 | 260 | |
305 | 323 | err = f.Close() |
306 | 324 | assert.NoError(t, err) |
307 | 325 | |
308 | n, err = r2.Read(b) | |
326 | _, err = r2.Read(b) | |
309 | 327 | assert.EqualError(t, err, io.EOF.Error()) |
310 | 328 | |
311 | 329 | assert.NoError(t, checkWgDone(leakCheckWg)) |
330 | } | |
331 | ||
332 | func TestFifoCloseError(t *testing.T) { | |
333 | tmpdir, err := os.MkdirTemp("", "fifos") | |
334 | assert.NoError(t, err) | |
335 | defer os.RemoveAll(tmpdir) | |
336 | ||
337 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) | |
338 | defer cancel() | |
339 | ||
340 | w, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
341 | assert.NoError(t, err) | |
342 | w.Close() | |
343 | ||
344 | data := []byte("hello world!") | |
345 | _, err = w.Write(data) | |
346 | assert.Equal(t, ErrWriteClosed, err) | |
347 | ||
348 | r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
349 | assert.NoError(t, err) | |
350 | r.Close() | |
351 | ||
352 | buf := make([]byte, len(data)) | |
353 | _, err = r.Read(buf) | |
354 | assert.Equal(t, ErrReadClosed, err) | |
355 | } | |
356 | ||
357 | func TestFifoCloseWhileReading(t *testing.T) { | |
358 | tmpdir, err := os.MkdirTemp("", "fifos") | |
359 | assert.NoError(t, err) | |
360 | defer os.RemoveAll(tmpdir) | |
361 | ||
362 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) | |
363 | defer cancel() | |
364 | ||
365 | r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
366 | assert.NoError(t, err) | |
367 | ||
368 | read := make(chan struct{}) | |
369 | readErr := make(chan error) | |
370 | ||
371 | go func() { | |
372 | buf := make([]byte, 32) | |
373 | _, err := r.Read(buf) | |
374 | ||
375 | if err != nil { | |
376 | readErr <- err | |
377 | return | |
378 | } | |
379 | ||
380 | close(read) | |
381 | ||
382 | }() | |
383 | ||
384 | time.Sleep(500 * time.Millisecond) | |
385 | r.Close() | |
386 | ||
387 | select { | |
388 | case <-read: | |
389 | t.Fatal("Read should not succeed") | |
390 | case err := <-readErr: | |
391 | assert.Equal(t, ErrReadClosed, err) | |
392 | case <-time.After(500 * time.Millisecond): | |
393 | t.Fatal("Read should not be blocked") | |
394 | } | |
395 | } | |
396 | ||
397 | func TestFifoCloseWhileReadingAndWriting(t *testing.T) { | |
398 | tmpdir, err := os.MkdirTemp("", "fifos") | |
399 | assert.NoError(t, err) | |
400 | defer os.RemoveAll(tmpdir) | |
401 | ||
402 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) | |
403 | defer cancel() | |
404 | ||
405 | r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
406 | assert.NoError(t, err) | |
407 | ||
408 | w, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0) | |
409 | assert.NoError(t, err) | |
410 | ||
411 | read := make(chan struct{}) | |
412 | readErr := make(chan error) | |
413 | wBuffer := []byte("foo") | |
414 | ||
415 | go func() { | |
416 | buf := make([]byte, 32) | |
417 | _, err := r.Read(buf) | |
418 | ||
419 | if err != nil { | |
420 | readErr <- err | |
421 | return | |
422 | } | |
423 | ||
424 | close(read) | |
425 | }() | |
426 | ||
427 | time.Sleep(500 * time.Millisecond) | |
428 | ||
429 | // Close the reader and then write in the writer. | |
430 | // The reader thread should return an error. | |
431 | r.Close() | |
432 | ||
433 | // The write should fail, the reader end of the pipe is closed. | |
434 | _, err = w.Write(wBuffer) | |
435 | assert.Error(t, err) | |
436 | ||
437 | select { | |
438 | case <-read: | |
439 | t.Fatal("Read should not succeed") | |
440 | case err := <-readErr: | |
441 | assert.Error(t, err) | |
442 | case <-time.After(500 * time.Millisecond): | |
443 | t.Fatal("Read should not be blocked") | |
444 | } | |
445 | } | |
446 | ||
447 | func TestFifoWrongRdWrError(t *testing.T) { | |
448 | tmpdir, err := os.MkdirTemp("", "fifos") | |
449 | assert.NoError(t, err) | |
450 | defer os.RemoveAll(tmpdir) | |
451 | ||
452 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) | |
453 | defer cancel() | |
454 | ||
455 | r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
456 | assert.NoError(t, err) | |
457 | ||
458 | data := []byte("hello world!") | |
459 | _, err = r.Write(data) | |
460 | assert.Equal(t, ErrWrToRDONLY, err) | |
461 | ||
462 | w, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
463 | assert.NoError(t, err) | |
464 | ||
465 | buf := make([]byte, len(data)) | |
466 | _, err = w.Read(buf) | |
467 | assert.Equal(t, ErrRdFrmWRONLY, err) | |
312 | 468 | } |
313 | 469 | |
314 | 470 | func checkWgDone(wg *sync.WaitGroup) error { |
0 | module github.com/containerd/fifo | |
1 | ||
2 | go 1.18 | |
3 | ||
4 | require ( | |
5 | github.com/stretchr/testify v1.8.0 | |
6 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 | |
7 | ) | |
8 | ||
9 | require ( | |
10 | github.com/davecgh/go-spew v1.1.1 // indirect | |
11 | github.com/pmezard/go-difflib v1.0.0 // indirect | |
12 | gopkg.in/yaml.v3 v3.0.1 // indirect | |
13 | ) |
0 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |
2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |
4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |
5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |
6 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | |
7 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |
8 | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= | |
9 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | |
10 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= | |
11 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |
12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |
13 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |
14 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |
15 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | |
16 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
0 | //go:build linux | |
0 | 1 | // +build linux |
2 | ||
3 | /* | |
4 | Copyright The containerd Authors. | |
5 | ||
6 | Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | you may not use this file except in compliance with the License. | |
8 | You may obtain a copy of the License at | |
9 | ||
10 | http://www.apache.org/licenses/LICENSE-2.0 | |
11 | ||
12 | Unless required by applicable law or agreed to in writing, software | |
13 | distributed under the License is distributed on an "AS IS" BASIS, | |
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | See the License for the specific language governing permissions and | |
16 | limitations under the License. | |
17 | */ | |
1 | 18 | |
2 | 19 | package fifo |
3 | 20 | |
6 | 23 | "os" |
7 | 24 | "sync" |
8 | 25 | "syscall" |
9 | ||
10 | "github.com/pkg/errors" | |
11 | 26 | ) |
12 | 27 | |
28 | //nolint:golint | |
13 | 29 | const O_PATH = 010000000 |
14 | 30 | |
15 | 31 | type handle struct { |
16 | 32 | f *os.File |
33 | fd uintptr | |
17 | 34 | dev uint64 |
18 | 35 | ino uint64 |
19 | 36 | closeOnce sync.Once |
23 | 40 | func getHandle(fn string) (*handle, error) { |
24 | 41 | f, err := os.OpenFile(fn, O_PATH, 0) |
25 | 42 | if err != nil { |
26 | return nil, errors.Wrapf(err, "failed to open %v with O_PATH", fn) | |
43 | return nil, fmt.Errorf("failed to open %v with O_PATH: %w", fn, err) | |
27 | 44 | } |
28 | 45 | |
29 | var stat syscall.Stat_t | |
30 | if err := syscall.Fstat(int(f.Fd()), &stat); err != nil { | |
46 | var ( | |
47 | stat syscall.Stat_t | |
48 | fd = f.Fd() | |
49 | ) | |
50 | if err := syscall.Fstat(int(fd), &stat); err != nil { | |
31 | 51 | f.Close() |
32 | return nil, errors.Wrapf(err, "failed to stat handle %v", f.Fd()) | |
52 | return nil, fmt.Errorf("failed to stat handle %v: %w", fd, err) | |
33 | 53 | } |
34 | 54 | |
35 | 55 | h := &handle{ |
36 | 56 | f: f, |
37 | 57 | name: fn, |
38 | dev: stat.Dev, | |
39 | ino: stat.Ino, | |
58 | //nolint:unconvert | |
59 | dev: uint64(stat.Dev), | |
60 | ino: stat.Ino, | |
61 | fd: fd, | |
40 | 62 | } |
41 | 63 | |
42 | 64 | // check /proc just in case |
43 | 65 | if _, err := os.Stat(h.procPath()); err != nil { |
44 | 66 | f.Close() |
45 | return nil, errors.Wrapf(err, "couldn't stat %v", h.procPath()) | |
67 | return nil, fmt.Errorf("couldn't stat %v: %w", h.procPath(), err) | |
46 | 68 | } |
47 | 69 | |
48 | 70 | return h, nil |
49 | 71 | } |
50 | 72 | |
51 | 73 | func (h *handle) procPath() string { |
52 | return fmt.Sprintf("/proc/self/fd/%d", h.f.Fd()) | |
74 | return fmt.Sprintf("/proc/self/fd/%d", h.fd) | |
53 | 75 | } |
54 | 76 | |
55 | 77 | func (h *handle) Name() string { |
59 | 81 | func (h *handle) Path() (string, error) { |
60 | 82 | var stat syscall.Stat_t |
61 | 83 | if err := syscall.Stat(h.procPath(), &stat); err != nil { |
62 | return "", errors.Wrapf(err, "path %v could not be statted", h.procPath()) | |
84 | return "", fmt.Errorf("path %v could not be statted: %w", h.procPath(), err) | |
63 | 85 | } |
64 | if stat.Dev != h.dev || stat.Ino != h.ino { | |
65 | return "", errors.Errorf("failed to verify handle %v/%v %v/%v", stat.Dev, h.dev, stat.Ino, h.ino) | |
86 | //nolint:unconvert | |
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) | |
66 | 89 | } |
67 | 90 | return h.procPath(), nil |
68 | 91 | } |
0 | // +build !linux | |
0 | //go:build !linux && !windows | |
1 | // +build !linux,!windows | |
2 | ||
3 | /* | |
4 | Copyright The containerd Authors. | |
5 | ||
6 | Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | you may not use this file except in compliance with the License. | |
8 | You may obtain a copy of the License at | |
9 | ||
10 | http://www.apache.org/licenses/LICENSE-2.0 | |
11 | ||
12 | Unless required by applicable law or agreed to in writing, software | |
13 | distributed under the License is distributed on an "AS IS" BASIS, | |
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | See the License for the specific language governing permissions and | |
16 | limitations under the License. | |
17 | */ | |
1 | 18 | |
2 | 19 | package fifo |
3 | 20 | |
4 | 21 | import ( |
22 | "fmt" | |
5 | 23 | "syscall" |
6 | ||
7 | "github.com/pkg/errors" | |
8 | 24 | ) |
9 | 25 | |
10 | 26 | type handle struct { |
16 | 32 | func getHandle(fn string) (*handle, error) { |
17 | 33 | var stat syscall.Stat_t |
18 | 34 | if err := syscall.Stat(fn, &stat); err != nil { |
19 | return nil, errors.Wrapf(err, "failed to stat %v", fn) | |
35 | return nil, fmt.Errorf("failed to stat %v: %w", fn, err) | |
20 | 36 | } |
21 | 37 | |
22 | 38 | h := &handle{ |
23 | 39 | fn: fn, |
24 | dev: uint64(stat.Dev), | |
25 | ino: stat.Ino, | |
40 | dev: uint64(stat.Dev), //nolint: unconvert | |
41 | ino: uint64(stat.Ino), //nolint: unconvert | |
26 | 42 | } |
27 | 43 | |
28 | 44 | return h, nil |
31 | 47 | func (h *handle) Path() (string, error) { |
32 | 48 | var stat syscall.Stat_t |
33 | 49 | if err := syscall.Stat(h.fn, &stat); err != nil { |
34 | return "", errors.Wrapf(err, "path %v could not be statted", h.fn) | |
50 | return "", fmt.Errorf("path %v could not be statted: %w", h.fn, err) | |
35 | 51 | } |
36 | if uint64(stat.Dev) != h.dev || stat.Ino != h.ino { | |
37 | return "", errors.Errorf("failed to verify handle %v/%v %v/%v for %v", stat.Dev, h.dev, stat.Ino, h.ino, h.fn) | |
52 | if uint64(stat.Dev) != h.dev || uint64(stat.Ino) != h.ino { //nolint: unconvert | |
53 | return "", fmt.Errorf("failed to verify handle %v/%v %v/%v for %v", stat.Dev, h.dev, stat.Ino, h.ino, h.fn) | |
38 | 54 | } |
39 | 55 | return h.fn, nil |
40 | 56 | } |
0 | // +build !solaris | |
1 | ||
2 | package fifo | |
3 | ||
4 | import "syscall" | |
5 | ||
6 | func mkfifo(path string, mode uint32) (err error) { | |
7 | return syscall.Mkfifo(path, mode) | |
8 | } |
0 | // +build solaris | |
1 | ||
2 | package fifo | |
3 | ||
4 | import ( | |
5 | "golang.org/x/sys/unix" | |
6 | ) | |
7 | ||
8 | func mkfifo(path string, mode uint32) (err error) { | |
9 | return unix.Mkfifo(path, mode) | |
10 | } |
0 | //go:build !windows | |
1 | // +build !windows | |
2 | ||
3 | /* | |
4 | Copyright The containerd Authors. | |
5 | ||
6 | Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | you may not use this file except in compliance with the License. | |
8 | You may obtain a copy of the License at | |
9 | ||
10 | http://www.apache.org/licenses/LICENSE-2.0 | |
11 | ||
12 | Unless required by applicable law or agreed to in writing, software | |
13 | distributed under the License is distributed on an "AS IS" BASIS, | |
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | See the License for the specific language governing permissions and | |
16 | limitations under the License. | |
17 | */ | |
18 | ||
19 | package fifo | |
20 | ||
21 | import ( | |
22 | "syscall" | |
23 | ) | |
24 | ||
25 | // SyscallConn provides raw access to the fifo's underlying filedescrptor. | |
26 | // See syscall.Conn for guarantees provided by this interface. | |
27 | func (f *fifo) SyscallConn() (syscall.RawConn, error) { | |
28 | // deterministic check for closed | |
29 | select { | |
30 | case <-f.closed: | |
31 | return nil, ErrClosed | |
32 | default: | |
33 | } | |
34 | ||
35 | select { | |
36 | case <-f.closed: | |
37 | return nil, ErrClosed | |
38 | case <-f.opened: | |
39 | return f.file.SyscallConn() | |
40 | default: | |
41 | } | |
42 | ||
43 | // Not opened and not closed, this means open is non-blocking AND it's not open yet | |
44 | // Use rawConn to deal with non-blocking open. | |
45 | rc := &rawConn{f: f, ready: make(chan struct{})} | |
46 | go func() { | |
47 | select { | |
48 | case <-f.closed: | |
49 | return | |
50 | case <-f.opened: | |
51 | rc.raw, rc.err = f.file.SyscallConn() | |
52 | close(rc.ready) | |
53 | } | |
54 | }() | |
55 | ||
56 | return rc, nil | |
57 | } | |
58 | ||
59 | type rawConn struct { | |
60 | f *fifo | |
61 | ready chan struct{} | |
62 | raw syscall.RawConn | |
63 | err error | |
64 | } | |
65 | ||
66 | func (r *rawConn) Control(f func(fd uintptr)) error { | |
67 | select { | |
68 | case <-r.f.closed: | |
69 | return ErrCtrlClosed | |
70 | case <-r.ready: | |
71 | } | |
72 | ||
73 | if r.err != nil { | |
74 | return r.err | |
75 | } | |
76 | ||
77 | return r.raw.Control(f) | |
78 | } | |
79 | ||
80 | func (r *rawConn) Read(f func(fd uintptr) (done bool)) error { | |
81 | if r.f.flag&syscall.O_WRONLY > 0 { | |
82 | return ErrRdFrmWRONLY | |
83 | } | |
84 | ||
85 | select { | |
86 | case <-r.f.closed: | |
87 | return ErrReadClosed | |
88 | case <-r.ready: | |
89 | } | |
90 | ||
91 | if r.err != nil { | |
92 | return r.err | |
93 | } | |
94 | ||
95 | return r.raw.Read(f) | |
96 | } | |
97 | ||
98 | func (r *rawConn) Write(f func(fd uintptr) (done bool)) error { | |
99 | if r.f.flag&(syscall.O_WRONLY|syscall.O_RDWR) == 0 { | |
100 | return ErrWrToRDONLY | |
101 | } | |
102 | ||
103 | select { | |
104 | case <-r.f.closed: | |
105 | return ErrWriteClosed | |
106 | case <-r.ready: | |
107 | } | |
108 | ||
109 | if r.err != nil { | |
110 | return r.err | |
111 | } | |
112 | ||
113 | return r.raw.Write(f) | |
114 | } |
0 | //go:build !windows | |
1 | // +build !windows | |
2 | ||
3 | /* | |
4 | Copyright The containerd Authors. | |
5 | ||
6 | Licensed under the Apache License, Version 2.0 (the "License"); | |
7 | you may not use this file except in compliance with the License. | |
8 | You may obtain a copy of the License at | |
9 | ||
10 | http://www.apache.org/licenses/LICENSE-2.0 | |
11 | ||
12 | Unless required by applicable law or agreed to in writing, software | |
13 | distributed under the License is distributed on an "AS IS" BASIS, | |
14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 | See the License for the specific language governing permissions and | |
16 | limitations under the License. | |
17 | */ | |
18 | ||
19 | package fifo | |
20 | ||
21 | import ( | |
22 | "bytes" | |
23 | "context" | |
24 | "io" | |
25 | "os" | |
26 | "path" | |
27 | "path/filepath" | |
28 | "syscall" | |
29 | "testing" | |
30 | "time" | |
31 | ||
32 | "github.com/stretchr/testify/assert" | |
33 | ) | |
34 | ||
35 | func TestRawReadWrite(t *testing.T) { | |
36 | tmpdir, err := os.MkdirTemp("", "fifos") | |
37 | assert.NoError(t, err) | |
38 | defer os.RemoveAll(tmpdir) | |
39 | ||
40 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) | |
41 | defer cancel() | |
42 | ||
43 | r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
44 | assert.NoError(t, err) | |
45 | defer r.Close() | |
46 | rawR := makeRawConn(t, r, false) | |
47 | assert.Error(t, rawR.Write(func(uintptr) bool { return true })) | |
48 | ||
49 | w, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_WRONLY|syscall.O_NONBLOCK, 0) | |
50 | assert.NoError(t, err) | |
51 | defer w.Close() | |
52 | rawW := makeRawConn(t, w, false) | |
53 | assert.Error(t, rawW.Read(func(uintptr) bool { return true })) | |
54 | ||
55 | data := []byte("hello world") | |
56 | rawWrite(t, rawW, data) | |
57 | ||
58 | dataR := make([]byte, len(data)) | |
59 | rawRead(t, rawR, dataR) | |
60 | assert.True(t, bytes.Equal(data, dataR)) | |
61 | } | |
62 | ||
63 | func TestRawWriteUserRead(t *testing.T) { | |
64 | tmpdir, err := os.MkdirTemp("", "fifos") | |
65 | assert.NoError(t, err) | |
66 | defer os.RemoveAll(tmpdir) | |
67 | ||
68 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) | |
69 | defer cancel() | |
70 | ||
71 | w, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
72 | assert.NoError(t, err) | |
73 | defer w.Close() | |
74 | rawW := makeRawConn(t, w, false) | |
75 | ||
76 | r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
77 | assert.NoError(t, err) | |
78 | defer r.Close() | |
79 | ||
80 | data := []byte("hello world!") | |
81 | rawWrite(t, rawW, data) | |
82 | w.Close() | |
83 | ||
84 | buf := make([]byte, len(data)) | |
85 | n, err := io.ReadFull(r, buf) | |
86 | assert.NoError(t, err) | |
87 | assert.True(t, bytes.Equal(data, buf[:n])) | |
88 | } | |
89 | ||
90 | func TestUserWriteRawRead(t *testing.T) { | |
91 | tmpdir, err := os.MkdirTemp("", "fifos") | |
92 | assert.NoError(t, err) | |
93 | defer os.RemoveAll(tmpdir) | |
94 | ||
95 | ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) | |
96 | defer cancel() | |
97 | ||
98 | w, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
99 | assert.NoError(t, err) | |
100 | defer w.Close() | |
101 | ||
102 | r, err := OpenFifo(ctx, filepath.Join(tmpdir, t.Name()), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
103 | assert.NoError(t, err) | |
104 | defer r.Close() | |
105 | rawR := makeRawConn(t, r, false) | |
106 | ||
107 | data := []byte("hello world!") | |
108 | n, err := w.Write(data) | |
109 | assert.NoError(t, err) | |
110 | assert.Equal(t, n, len(data)) | |
111 | w.Close() | |
112 | ||
113 | buf := make([]byte, len(data)) | |
114 | rawRead(t, rawR, buf) | |
115 | assert.True(t, bytes.Equal(data, buf[:n])) | |
116 | } | |
117 | ||
118 | func TestRawCloseError(t *testing.T) { | |
119 | tmpdir, err := os.MkdirTemp("", "fifos") | |
120 | assert.NoError(t, err) | |
121 | defer os.RemoveAll(tmpdir) | |
122 | ||
123 | t.Run("SyscallConnAfterClose", func(t *testing.T) { | |
124 | ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | |
125 | defer cancel() | |
126 | ||
127 | f, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_RDWR|syscall.O_CREAT, 0600) | |
128 | assert.NoError(t, err) | |
129 | ||
130 | f.Close() | |
131 | ||
132 | makeRawConn(t, f, true) | |
133 | }) | |
134 | ||
135 | t.Run("RawOpsAfterClose", func(t *testing.T) { | |
136 | ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | |
137 | defer cancel() | |
138 | f, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_RDWR|syscall.O_CREAT, 0600) | |
139 | assert.NoError(t, err) | |
140 | defer f.Close() | |
141 | ||
142 | raw := makeRawConn(t, f, false) | |
143 | ||
144 | f.Close() | |
145 | ||
146 | assert.Error(t, raw.Control(func(uintptr) {})) | |
147 | dummy := func(uintptr) bool { return true } | |
148 | assert.Error(t, raw.Write(dummy)) | |
149 | assert.Error(t, raw.Read(dummy)) | |
150 | }) | |
151 | ||
152 | t.Run("NonBlockRawOpsAfterClose", func(t *testing.T) { | |
153 | ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | |
154 | defer cancel() | |
155 | dummy := func(uintptr) bool { return true } | |
156 | r, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
157 | assert.NoError(t, err) | |
158 | defer r.Close() | |
159 | rawR := makeRawConn(t, r, false) | |
160 | r.Close() | |
161 | ||
162 | assert.Equal(t, ErrCtrlClosed, rawR.Control(func(uintptr) {})) | |
163 | assert.Equal(t, ErrReadClosed, rawR.Read(dummy)) | |
164 | ||
165 | w, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
166 | assert.NoError(t, err) | |
167 | defer w.Close() | |
168 | rawW := makeRawConn(t, w, false) | |
169 | w.Close() | |
170 | ||
171 | assert.Equal(t, ErrCtrlClosed, rawW.Control(func(uintptr) {})) | |
172 | assert.Equal(t, ErrWriteClosed, rawW.Write(dummy)) | |
173 | }) | |
174 | } | |
175 | ||
176 | func TestRawWrongRdWrError(t *testing.T) { | |
177 | tmpdir, err := os.MkdirTemp("", "fifos") | |
178 | assert.NoError(t, err) | |
179 | defer os.RemoveAll(tmpdir) | |
180 | ||
181 | ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) | |
182 | defer cancel() | |
183 | dummy := func(uintptr) bool { return true } | |
184 | r, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
185 | assert.NoError(t, err) | |
186 | defer r.Close() | |
187 | rawR := makeRawConn(t, r, false) | |
188 | ||
189 | assert.Equal(t, ErrWrToRDONLY, rawR.Write(dummy)) | |
190 | ||
191 | w, err := OpenFifo(ctx, filepath.Join(tmpdir, path.Base(t.Name())), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0600) | |
192 | assert.NoError(t, err) | |
193 | defer w.Close() | |
194 | rawW := makeRawConn(t, w, false) | |
195 | ||
196 | assert.Equal(t, ErrRdFrmWRONLY, rawW.Read(dummy)) | |
197 | } | |
198 | ||
199 | func makeRawConn(t *testing.T, fifo io.ReadWriteCloser, expectError bool) syscall.RawConn { | |
200 | sc, ok := fifo.(syscall.Conn) | |
201 | assert.True(t, ok, "not a syscall.Conn") | |
202 | ||
203 | raw, err := sc.SyscallConn() | |
204 | if !expectError { | |
205 | assert.NoError(t, err) | |
206 | } else { | |
207 | assert.Error(t, err) | |
208 | } | |
209 | ||
210 | return raw | |
211 | } | |
212 | ||
213 | func rawWrite(t *testing.T, rc syscall.RawConn, data []byte) { | |
214 | var written int | |
215 | var wErr error | |
216 | ||
217 | err := rc.Write(func(fd uintptr) bool { | |
218 | var n int | |
219 | n, wErr = syscall.Write(int(fd), data[written:]) | |
220 | written += n | |
221 | if wErr != nil || n == 0 || written == len(data) { | |
222 | return true | |
223 | } | |
224 | return false | |
225 | }) | |
226 | assert.NoError(t, err) | |
227 | assert.NoError(t, wErr) | |
228 | assert.Equal(t, written, len(data)) | |
229 | } | |
230 | ||
231 | func rawRead(t *testing.T, rc syscall.RawConn, data []byte) { | |
232 | var ( | |
233 | rErr error | |
234 | read int | |
235 | ) | |
236 | ||
237 | err := rc.Read(func(fd uintptr) bool { | |
238 | var n int | |
239 | n, rErr = syscall.Read(int(fd), data[read:]) | |
240 | read += n | |
241 | if rErr != nil || n == 0 || read == len(data) { | |
242 | return true | |
243 | } | |
244 | return false | |
245 | }) | |
246 | assert.NoError(t, err) | |
247 | assert.NoError(t, rErr) | |
248 | assert.Equal(t, read, len(data)) | |
249 | } |
0 | 0 | ### fifo |
1 | ||
2 | [![PkgGoDev](https://pkg.go.dev/badge/github.com/containerd/fifo)](https://pkg.go.dev/github.com/containerd/fifo) | |
3 | [![Build Status](https://github.com/containerd/fifo/workflows/CI/badge.svg)](https://github.com/containerd/fifo/actions?query=workflow%3ACI) | |
4 | [![codecov](https://codecov.io/gh/containerd/fifo/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/fifo) | |
5 | [![Go Report Card](https://goreportcard.com/badge/github.com/containerd/fifo)](https://goreportcard.com/report/github.com/containerd/fifo) | |
1 | 6 | |
2 | 7 | Go package for handling fifos in a sane way. |
3 | 8 | |
26 | 31 | // Close the fifo. Next reads/writes will error. This method can also be used |
27 | 32 | // before open(2) has returned and fifo was never opened. |
28 | 33 | func (f *fifo) Close() error |
29 | ```⏎ | |
34 | ``` | |
35 | ||
36 | ## Project details | |
37 | ||
38 | The fifo is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). | |
39 | As a containerd sub-project, you will find the: | |
40 | ||
41 | * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), | |
42 | * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), | |
43 | * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) | |
44 | ||
45 | information in our [`containerd/project`](https://github.com/containerd/project) repository. |
0 | /* | |
1 | Copyright The containerd Authors. | |
2 | ||
3 | Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | you may not use this file except in compliance with the License. | |
5 | You may obtain a copy of the License at | |
6 | ||
7 | http://www.apache.org/licenses/LICENSE-2.0 | |
8 | ||
9 | Unless required by applicable law or agreed to in writing, software | |
10 | distributed under the License is distributed on an "AS IS" BASIS, | |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | See the License for the specific language governing permissions and | |
13 | limitations under the License. | |
14 | */ | |
15 | ||
16 | package fifo | |
17 | ||
18 | import "os" | |
19 | ||
20 | // IsFifo checks if a file is a (named pipe) fifo | |
21 | // if the file does not exist then it returns false | |
22 | func IsFifo(path string) (bool, error) { | |
23 | stat, err := os.Stat(path) | |
24 | if err != nil { | |
25 | if os.IsNotExist(err) { | |
26 | return false, nil | |
27 | } | |
28 | return false, err | |
29 | } | |
30 | if stat.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { | |
31 | return true, nil | |
32 | } | |
33 | return false, nil | |
34 | } |