in internal/pkg/agent/application/upgrade/step_unpack.go [81:207]
func unzip(log *logger.Logger, archivePath, dataDir string, flavor string) (UnpackResult, error) {
var hash, rootDir string
r, err := zip.OpenReader(archivePath)
if err != nil {
return UnpackResult{}, err
}
defer r.Close()
fileNamePrefix := strings.TrimSuffix(filepath.Base(archivePath), ".zip") + "/" // omitting `elastic-agent-{version}-{os}-{arch}/` in filename
pm := pathMapper{}
var versionedHome string
metadata, err := getPackageMetadataFromZipReader(r, fileNamePrefix)
if err != nil {
return UnpackResult{}, fmt.Errorf("retrieving package metadata from %q: %w", archivePath, err)
}
hash = metadata.hash[:hashLen]
var registry map[string][]string
if metadata.manifest != nil {
pm.mappings = metadata.manifest.Package.PathMappings
versionedHome = filepath.FromSlash(pm.Map(metadata.manifest.Package.VersionedHome))
registry = metadata.manifest.Package.Flavors
} else {
// if at this point we didn't load the manifest, set the versioned to the backup value
versionedHome = createVersionedHomeFromHash(hash)
}
skipFn, err := skipFnFromZip(log, r, flavor, fileNamePrefix, createVersionedHomeFromHash(hash), registry)
if err != nil {
return UnpackResult{}, err
}
unpackFile := func(f *zip.File) (err error) {
rc, err := f.Open()
if err != nil {
return err
}
defer func() {
if cerr := rc.Close(); cerr != nil {
err = goerrors.Join(err, cerr)
}
}()
fileName := strings.TrimPrefix(f.Name, fileNamePrefix)
if fileName == agentCommitFile {
// we already loaded the hash, skip this one
return nil
}
mappedPackagePath := pm.Map(fileName)
// skip everything outside data/
if !strings.HasPrefix(mappedPackagePath, "data/") {
return nil
}
dstPath := strings.TrimPrefix(mappedPackagePath, "data/")
dstPath = filepath.Join(dataDir, dstPath)
if skipFn(dstPath) {
return nil
}
if f.FileInfo().IsDir() {
log.Debugw("Unpacking directory", "archive", "zip", "file.path", dstPath)
// check if the directory already exists
_, err = os.Stat(dstPath)
if errors.Is(err, fs.ErrNotExist) {
// the directory does not exist, create it and any non-existing parent directory with the same permissions
if err := os.MkdirAll(dstPath, f.Mode().Perm()&0770); err != nil {
return fmt.Errorf("creating directory %q: %w", dstPath, err)
}
} else if err != nil {
return fmt.Errorf("stat() directory %q: %w", dstPath, err)
} else {
// directory already exists, set the appropriate permissions
err = os.Chmod(dstPath, f.Mode().Perm()&0770)
if err != nil {
return fmt.Errorf("setting permissions %O for directory %q: %w", f.Mode().Perm()&0770, dstPath, err)
}
}
_ = os.MkdirAll(dstPath, f.Mode()&0770)
} else {
log.Debugw("Unpacking file", "archive", "zip", "file.path", dstPath)
// create non-existing containing folders with 0770 permissions right now, we'll fix the permission of each
// directory as we come across them while processing the other package entries
_ = os.MkdirAll(filepath.Dir(dstPath), 0770)
f, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()&0770)
if err != nil {
return err
}
defer func() {
if cerr := f.Close(); cerr != nil {
err = goerrors.Join(err, cerr)
}
}()
//nolint:gosec // legacy
if _, err = io.Copy(f, rc); err != nil {
return err
}
}
return nil
}
for _, f := range r.File {
if rootDir == "" && filepath.Base(f.Name) == filepath.Dir(f.Name) {
// skip top level files
continue
}
if currentDir := filepath.Dir(f.Name); rootDir == "" || len(currentDir) < len(rootDir) {
rootDir = currentDir
}
if err := unpackFile(f); err != nil {
return UnpackResult{}, err
}
}
return UnpackResult{
Hash: hash,
VersionedHome: versionedHome,
}, nil
}