MCPcopy Create free account
hub / github.com/coder/coder / extractArchive

Function extractArchive

provisionersdk/tfpath/tfpath.go:97–184  ·  view source on GitHub ↗
(ctx context.Context, logger slog.Logger, fs afero.Fs, directory string, archive []byte)

Source from the content-addressed store, hash-verified

95}
96
97func extractArchive(ctx context.Context, logger slog.Logger, fs afero.Fs, directory string, archive []byte) error {
98 logger.Info(ctx, "unpacking source archive",
99 slog.F("size_bytes", len(archive)),
100 )
101
102 err := fs.MkdirAll(directory, 0o700)
103 if err != nil {
104 return xerrors.Errorf("create work directory %q: %w", directory, err)
105 }
106
107 reader := tar.NewReader(bytes.NewBuffer(archive))
108 for {
109 header, err := reader.Next()
110 if err != nil {
111 if xerrors.Is(err, io.EOF) {
112 break
113 }
114 return xerrors.Errorf("read template source archive: %w", err)
115 }
116 logger.Debug(context.Background(), "read archive entry",
117 slog.F("name", header.Name),
118 slog.F("mod_time", header.ModTime),
119 slog.F("size", header.Size))
120
121 // Security: don't untar absolute or relative paths, as this can allow a malicious tar to overwrite
122 // files outside the workdir.
123 if !filepath.IsLocal(header.Name) {
124 return xerrors.Errorf("refusing to extract to non-local path")
125 }
126
127 // nolint: gosec // Safe to no-lint because the filepath.IsLocal check above.
128 headerPath := filepath.Join(directory, header.Name)
129 if !strings.HasPrefix(headerPath, filepath.Clean(directory)) {
130 return xerrors.New("tar attempts to target relative upper directory")
131 }
132 mode := header.FileInfo().Mode()
133 if mode == 0 {
134 mode = 0o600
135 }
136
137 // Always check for context cancellation before reading the next header.
138 // This is mainly important for unit tests, since a canceled context means
139 // the underlying directory is going to be deleted. There still exists
140 // the small race condition that the context is canceled after this, and
141 // before the disk write.
142 if ctx.Err() != nil {
143 return xerrors.Errorf("context canceled: %w", ctx.Err())
144 }
145 switch header.Typeflag {
146 case tar.TypeDir:
147 err = fs.MkdirAll(headerPath, mode)
148 if err != nil {
149 return xerrors.Errorf("mkdir %q: %w", headerPath, err)
150 }
151 logger.Debug(context.Background(), "extracted directory",
152 slog.F("path", headerPath),
153 slog.F("mode", fmt.Sprintf("%O", mode)))
154 case tar.TypeReg:

Callers 1

ExtractArchiveMethod · 0.85

Calls 8

MkdirAllMethod · 0.80
ErrMethod · 0.80
NextMethod · 0.65
NewMethod · 0.65
CloseMethod · 0.65
InfoMethod · 0.45
ErrorfMethod · 0.45
IsMethod · 0.45

Tested by

no test coverage detected