Files
go-dpkg/dpkg/reader.go
Matheus Sampaio Queiroga fb6024ec5d big update and move dpkg module
Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
2025-03-13 14:40:14 -03:00

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
}