MCPcopy
hub / github.com/docker/compose / writeEntry

Method writeEntry

internal/sync/tar.go:173–245  ·  view source on GitHub ↗
(entry archiveEntry)

Source from the content-addressed store, hash-verified

171}
172
173func (a *ArchiveBuilder) writeEntry(entry archiveEntry) error {
174 pathInTar := entry.path
175 header := entry.header
176
177 if header.Typeflag != tar.TypeReg {
178 // anything other than a regular file (e.g. dir, symlink) just needs the header
179 if err := a.tw.WriteHeader(header); err != nil {
180 return fmt.Errorf("writing %q header: %w", pathInTar, err)
181 }
182 return nil
183 }
184
185 file, err := os.Open(pathInTar)
186 if err != nil {
187 // In case the file has been deleted since we last looked at it.
188 if os.IsNotExist(err) {
189 return nil
190 }
191 return err
192 }
193
194 defer func() {
195 _ = file.Close()
196 }()
197
198 // The size header must match the number of contents bytes.
199 //
200 // There is room for a race condition here if something writes to the file
201 // after we've read the file size.
202 //
203 // For small files, we avoid this by first copying the file into a buffer,
204 // and using the size of the buffer to populate the header.
205 //
206 // For larger files, we don't want to copy the whole thing into a buffer,
207 // because that would blow up heap size. There is some danger that this
208 // will lead to a spurious error when the tar writer validates the sizes.
209 // That error will be disruptive but will be handled as best as we
210 // can downstream.
211 useBuf := header.Size < 5000000
212 if useBuf {
213 a.copyBuf.Reset()
214 _, err = io.Copy(a.copyBuf, file)
215 if err != nil && !errors.Is(err, io.EOF) {
216 return fmt.Errorf("copying %q: %w", pathInTar, err)
217 }
218 header.Size = int64(len(a.copyBuf.Bytes()))
219 }
220
221 // wait to write the header until _after_ the file is successfully opened
222 // to avoid generating an invalid tar entry that has a header but no contents
223 // in the case the file has been deleted
224 err = a.tw.WriteHeader(header)
225 if err != nil {
226 return fmt.Errorf("writing %q header: %w", pathInTar, err)
227 }
228
229 if useBuf {
230 _, err = io.Copy(a.tw, a.copyBuf)

Callers 1

ArchivePathsIfExistMethod · 0.95

Calls 3

BytesMethod · 0.80
CloseMethod · 0.65
CopyMethod · 0.65

Tested by

no test coverage detected