Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
142 lines
3.7 KiB
Go
142 lines
3.7 KiB
Go
package dpkg
|
|
|
|
import (
|
|
"archive/tar"
|
|
"fmt"
|
|
"io"
|
|
"path"
|
|
|
|
"sirherobrine23.com.br/sirherobrine23/go-dpkg/ar"
|
|
"sirherobrine23.com.br/sirherobrine23/go-dpkg/internal/descompress"
|
|
)
|
|
|
|
func tarReader(r io.Reader) (*tar.Reader, io.Closer, error) {
|
|
tarballFile, err := descompress.Descompress(r)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return tar.NewReader(tarballFile), tarballFile, nil
|
|
}
|
|
|
|
// Parse a dpkg file and return a Dpkg struct and data.tar reader without compression
|
|
func ParseDpkg(r io.Reader) (*Dpkg, io.ReadCloser, error) {
|
|
dpkgFile, err := ar.NewReader(r)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
head, err := dpkgFile.Next()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
} else if head.Filename != "debian-binary" {
|
|
return nil, nil, ErrInvalidDebian
|
|
}
|
|
dpkgFile.Read(make([]byte, 4))
|
|
|
|
if head, err = dpkgFile.Next(); err != nil {
|
|
return nil, nil, fmt.Errorf("cannot get control.tar: %s", err)
|
|
} else if head.Filename[:11] != "control.tar" {
|
|
return nil, nil, ErrInvalidDebian
|
|
}
|
|
|
|
controller, closerDescompress, err := tarReader(dpkgFile)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("cannot extract control.tar file: %s", err)
|
|
}
|
|
defer closerDescompress.Close()
|
|
|
|
dpkg := &Dpkg{Pkg: &Package{}}
|
|
for {
|
|
head, err := controller.Next()
|
|
if err != nil && err == io.EOF {
|
|
break
|
|
} else if err != nil {
|
|
return nil, nil, fmt.Errorf("cannot get file header from control.tar: %s", err)
|
|
}
|
|
|
|
switch path.Base(head.Name) {
|
|
case "control":
|
|
header, err := io.ReadAll(controller)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
} else if err = dpkg.Pkg.UnmarshalBinary(header); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
case "postinst", "preinst", "prerm", "postrm":
|
|
script, err := io.ReadAll(controller)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
} else if dpkg.Scripts == nil {
|
|
dpkg.Scripts = &Scripts{}
|
|
}
|
|
switch path.Base(head.Name) {
|
|
case "postinst":
|
|
dpkg.Scripts.PostInstall = script
|
|
case "preinst":
|
|
dpkg.Scripts.PreInstall = script
|
|
case "prerm":
|
|
dpkg.Scripts.PostRemove = script
|
|
case "postrm":
|
|
dpkg.Scripts.PostRemove = script
|
|
}
|
|
case "old-postinst", "old-preinst", "old-prerm", "old-postrm":
|
|
script, err := io.ReadAll(controller)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
} else if dpkg.OldScripts == nil {
|
|
dpkg.OldScripts = &Scripts{}
|
|
}
|
|
switch path.Base(head.Name) {
|
|
case "old-postinst":
|
|
dpkg.OldScripts.PostInstall = script
|
|
case "old-preinst":
|
|
dpkg.OldScripts.PreInstall = script
|
|
case "old-prerm":
|
|
dpkg.OldScripts.PostRemove = script
|
|
case "old-postrm":
|
|
dpkg.OldScripts.PostRemove = script
|
|
}
|
|
case "new-postinst", "new-preinst", "new-prerm", "new-postrm":
|
|
script, err := io.ReadAll(controller)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
} else if dpkg.NewScripts == nil {
|
|
dpkg.NewScripts = &Scripts{}
|
|
}
|
|
switch path.Base(head.Name) {
|
|
case "new-postinst":
|
|
dpkg.NewScripts.PostInstall = script
|
|
case "new-preinst":
|
|
dpkg.NewScripts.PreInstall = script
|
|
case "new-prerm":
|
|
dpkg.NewScripts.PostRemove = script
|
|
case "new-postrm":
|
|
dpkg.NewScripts.PostRemove = script
|
|
}
|
|
default:
|
|
if !head.FileInfo().Mode().IsDir() {
|
|
io.Copy(io.Discard, controller)
|
|
}
|
|
}
|
|
}
|
|
|
|
if head, err = dpkgFile.Next(); err != nil {
|
|
if err != io.EOF {
|
|
return nil, nil, fmt.Errorf("cannot get data.tar: %s", err)
|
|
}
|
|
io.Copy(io.Discard, dpkgFile) // Ignore the last byte if the size is odd
|
|
if head, err = dpkgFile.Next(); err != nil {
|
|
return nil, nil, fmt.Errorf("cannot get data.tar: %s", err)
|
|
}
|
|
}
|
|
|
|
if head.Filename[:8] != "data.tar" {
|
|
return nil, nil, ErrInvalidDebian
|
|
}
|
|
|
|
dpkg.Ext = path.Ext(head.Filename)
|
|
dpkg.Size = head.Size
|
|
data, err := descompress.Descompress(dpkgFile)
|
|
return dpkg, data, err
|
|
}
|