mirror of
https://github.com/mudler/luet.git
synced 2025-09-10 03:29:16 +00:00
Create helpers.UntarProtect for handle protected files
Currently, it's used the archive.ReplaceFileTarWrapper that requite a []byte of the files replaced. This is not a good idea if files are big and instead could be better in the near future reimplement ReplaceFileTarWrapper with a callback that return io.Reader instead of []byte. If a protected file is already present on target rootfs it is created a file with the same prefix used in Gentoo: ._cfgXXXX_<filename>
This commit is contained in:
@@ -80,6 +80,9 @@ var installCmd = &cobra.Command{
|
|||||||
|
|
||||||
Debug("Solver", LuetCfg.GetSolverOptions().CompactString())
|
Debug("Solver", LuetCfg.GetSolverOptions().CompactString())
|
||||||
|
|
||||||
|
// Load config protect configs
|
||||||
|
installer.LoadConfigProtectConfs(LuetCfg)
|
||||||
|
|
||||||
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{
|
inst := installer.NewLuetInstaller(installer.LuetInstallerOptions{
|
||||||
Concurrency: LuetCfg.GetGeneral().Concurrency,
|
Concurrency: LuetCfg.GetGeneral().Concurrency,
|
||||||
SolverOptions: *LuetCfg.GetSolverOptions(),
|
SolverOptions: *LuetCfg.GetSolverOptions(),
|
||||||
|
@@ -18,6 +18,8 @@ package compiler
|
|||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@@ -277,8 +279,70 @@ func (a *PackageArtifact) Compress(src string, concurrency int) error {
|
|||||||
return errors.New("Compression type must be supplied")
|
return errors.New("Compression type must be supplied")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tarModifierWrapperFunc(dst, path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
|
||||||
|
// If the destination path already exists I rename target file name with postfix.
|
||||||
|
var destPath string
|
||||||
|
|
||||||
|
// Read data. TODO: We need change archive callback to permit to return a Reader
|
||||||
|
buffer := bytes.Buffer{}
|
||||||
|
if content != nil {
|
||||||
|
if _, err := buffer.ReadFrom(content); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch header.Typeflag {
|
||||||
|
case tar.TypeReg:
|
||||||
|
destPath = filepath.Join(dst, path)
|
||||||
|
default:
|
||||||
|
// Nothing to do. I return original reader
|
||||||
|
return header, buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if exists
|
||||||
|
if helpers.Exists(destPath) {
|
||||||
|
for i := 1; i < 1000; i++ {
|
||||||
|
name := filepath.Join(dst, filepath.Join(filepath.Dir(path), fmt.Sprintf("_cfg%04d_%s", i, filepath.Base(path))))
|
||||||
|
if helpers.Exists(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return &tar.Header{Mode: header.Mode, Typeflag: header.Typeflag, Name: name}, buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return header, buffer.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *PackageArtifact) GetProtectFiles() []string {
|
||||||
|
ans := []string{}
|
||||||
|
|
||||||
|
if LuetCfg.GetConfigProtectConfFiles() != nil && len(LuetCfg.GetConfigProtectConfFiles()) > 0 {
|
||||||
|
for _, file := range a.Files {
|
||||||
|
|
||||||
|
for _, conf := range LuetCfg.GetConfigProtectConfFiles() {
|
||||||
|
for _, dir := range conf.Directories {
|
||||||
|
if match, _ := filepath.Match(fmt.Sprintf("%s/*", dir), file); match {
|
||||||
|
ans = append(ans, file)
|
||||||
|
goto nextFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextFile:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans
|
||||||
|
}
|
||||||
|
|
||||||
// Unpack Untar and decompress (TODO) to the given path
|
// Unpack Untar and decompress (TODO) to the given path
|
||||||
func (a *PackageArtifact) Unpack(dst string, keepPerms bool) error {
|
func (a *PackageArtifact) Unpack(dst string, keepPerms bool) error {
|
||||||
|
|
||||||
|
// Create
|
||||||
|
protectedFiles := a.GetProtectFiles()
|
||||||
|
|
||||||
|
tarModifier := helpers.NewTarModifierWrapper(dst, tarModifierWrapperFunc)
|
||||||
|
|
||||||
switch a.CompressionType {
|
switch a.CompressionType {
|
||||||
case GZip:
|
case GZip:
|
||||||
// Create the uncompressed archive
|
// Create the uncompressed archive
|
||||||
@@ -307,15 +371,16 @@ func (a *PackageArtifact) Unpack(dst string, keepPerms bool) error {
|
|||||||
return errors.Wrap(err, "Cannot copy to "+a.GetPath()+".uncompressed")
|
return errors.Wrap(err, "Cannot copy to "+a.GetPath()+".uncompressed")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = helpers.Untar(a.GetPath()+".uncompressed", dst,
|
err = helpers.UntarProtect(a.GetPath()+".uncompressed", dst,
|
||||||
LuetCfg.GetGeneral().SameOwner)
|
LuetCfg.GetGeneral().SameOwner, protectedFiles, tarModifier)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
// Defaults to tar only (covers when "none" is supplied)
|
// Defaults to tar only (covers when "none" is supplied)
|
||||||
default:
|
default:
|
||||||
return helpers.Untar(a.GetPath(), dst, LuetCfg.GetGeneral().SameOwner)
|
return helpers.UntarProtect(a.GetPath(), dst, LuetCfg.GetGeneral().SameOwner,
|
||||||
|
protectedFiles, tarModifier)
|
||||||
}
|
}
|
||||||
return errors.New("Compression type must be supplied")
|
return errors.New("Compression type must be supplied")
|
||||||
}
|
}
|
||||||
|
@@ -204,6 +204,8 @@ type LuetConfig struct {
|
|||||||
ConfigProtectConfDir []string `mapstructure:"config_protect_confdir"`
|
ConfigProtectConfDir []string `mapstructure:"config_protect_confdir"`
|
||||||
CacheRepositories []LuetRepository `mapstructure:"repetitors"`
|
CacheRepositories []LuetRepository `mapstructure:"repetitors"`
|
||||||
SystemRepositories []LuetRepository `mapstructure:"repositories"`
|
SystemRepositories []LuetRepository `mapstructure:"repositories"`
|
||||||
|
|
||||||
|
ConfigProtectConfFiles []ConfigProtectConfFile
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLuetConfig(viper *v.Viper) *LuetConfig {
|
func NewLuetConfig(viper *v.Viper) *LuetConfig {
|
||||||
@@ -212,7 +214,7 @@ func NewLuetConfig(viper *v.Viper) *LuetConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenDefault(viper)
|
GenDefault(viper)
|
||||||
return &LuetConfig{Viper: viper}
|
return &LuetConfig{Viper: viper, ConfigProtectConfFiles: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenDefault(viper *v.Viper) {
|
func GenDefault(viper *v.Viper) {
|
||||||
@@ -275,6 +277,18 @@ func (c *LuetConfig) GetSolverOptions() *LuetSolverOptions {
|
|||||||
return &c.Solver
|
return &c.Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *LuetConfig) GetConfigProtectConfFiles() []ConfigProtectConfFile {
|
||||||
|
return c.ConfigProtectConfFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *LuetConfig) AddConfigProtectConfFile(file *ConfigProtectConfFile) {
|
||||||
|
if c.ConfigProtectConfFiles == nil {
|
||||||
|
c.ConfigProtectConfFiles = []ConfigProtectConfFile{*file}
|
||||||
|
} else {
|
||||||
|
c.ConfigProtectConfFiles = append(c.ConfigProtectConfFiles, *file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *LuetConfig) GetSystemRepository(name string) (*LuetRepository, error) {
|
func (c *LuetConfig) GetSystemRepository(name string) (*LuetRepository, error) {
|
||||||
var ans *LuetRepository = nil
|
var ans *LuetRepository = nil
|
||||||
|
|
||||||
|
32
pkg/config/config_protect.go
Normal file
32
pkg/config/config_protect.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright © 2019-2020 Ettore Di Giacinto <mudler@gentoo.org>
|
||||||
|
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package config
|
||||||
|
|
||||||
|
type ConfigProtectConfFile struct {
|
||||||
|
Filename string
|
||||||
|
|
||||||
|
Name string `mapstructure:"name"`
|
||||||
|
Directories []string `mapstructure:"dirs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfigProtectConfFile(filename string) *ConfigProtectConfFile {
|
||||||
|
return &ConfigProtectConfFile{
|
||||||
|
Filename: filename,
|
||||||
|
Name: "",
|
||||||
|
Directories: []string{},
|
||||||
|
}
|
||||||
|
}
|
86
pkg/installer/config_protect.go
Normal file
86
pkg/installer/config_protect.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright © 2019-2020 Ettore Di Giacinto <mudler@gentoo.org>
|
||||||
|
// Daniele Rondina <geaaru@sabayonlinux.org>
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License along
|
||||||
|
// with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package installer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/ghodss/yaml"
|
||||||
|
|
||||||
|
. "github.com/mudler/luet/pkg/config"
|
||||||
|
. "github.com/mudler/luet/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LoadConfigProtectConfs(c *LuetConfig) error {
|
||||||
|
var regexConfs = regexp.MustCompile(`.yml$`)
|
||||||
|
|
||||||
|
for _, cdir := range c.ConfigProtectConfDir {
|
||||||
|
Debug("Parsing Config Protect Directory", cdir, "...")
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(cdir)
|
||||||
|
if err != nil {
|
||||||
|
Debug("Skip dir", cdir, ":", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
if file.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !regexConfs.MatchString(file.Name()) {
|
||||||
|
Debug("File", file.Name(), "skipped.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
content, err := ioutil.ReadFile(path.Join(cdir, file.Name()))
|
||||||
|
if err != nil {
|
||||||
|
Warning("On read file", file.Name(), ":", err.Error())
|
||||||
|
Warning("File", file.Name(), "skipped.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := LoadConfigProtectConFile(file.Name(), content)
|
||||||
|
if err != nil {
|
||||||
|
Warning("On parse file", file.Name(), ":", err.Error())
|
||||||
|
Warning("File", file.Name(), "skipped.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Name == "" || len(r.Directories) == 0 {
|
||||||
|
Warning("Invalid config protect file", file.Name())
|
||||||
|
Warning("File", file.Name(), "skipped.")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
c.AddConfigProtectConfFile(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfigProtectConFile(filename string, data []byte) (*ConfigProtectConfFile, error) {
|
||||||
|
ans := NewConfigProtectConfFile(filename)
|
||||||
|
err := yaml.Unmarshal(data, &ans)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ans, nil
|
||||||
|
}
|
Reference in New Issue
Block a user