afl-transmit/logistic/unpacker.go

94 lines
2.4 KiB
Go
Raw Permalink Normal View History

2020-06-19 13:31:20 +00:00
package logistic
import (
"archive/tar"
"bytes"
2020-06-19 23:06:47 +00:00
"compress/flate"
2020-06-19 13:31:20 +00:00
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path"
"strings"
2020-06-19 13:31:20 +00:00
)
// UnpackInto decrompesses the given bytes with DEFLATE, then unpacks the result as TAR archive into the targetDir
2020-06-19 13:31:20 +00:00
func UnpackInto(raw []byte, targetDir string) error {
2020-06-19 23:06:47 +00:00
// Prepare FLATE decompressor
var flateBuffer bytes.Buffer
flateReader := flate.NewReader(&flateBuffer)
// Uncompress
flateBuffer.Write(raw)
raw, _ = ioutil.ReadAll(flateReader)
2020-06-19 13:31:20 +00:00
// Open TAR archive
var tarBuffer bytes.Buffer
tarBuffer.Write(raw)
tarReader := tar.NewReader(&tarBuffer)
// Create queue directory if it doesn't exist yet
_, folderErr := os.Stat(targetDir)
if os.IsNotExist(folderErr) {
os.Mkdir(targetDir, 0755)
}
2020-06-19 13:31:20 +00:00
// Iterate over all files in the archive
for {
// Read header
header, headerErr := tarReader.Next()
if headerErr == io.EOF {
// We reached the end of the TAR archive. Fine.
break
} else if headerErr != nil {
// Unknown error occurred
log.Printf("Error parsing TAR header entry: %s", headerErr)
break
}
// Write file
var fileBuffer bytes.Buffer
io.Copy(&fileBuffer, tarReader)
unpackSingleFile(fileBuffer.Bytes(), targetDir, header.Name)
}
return nil
}
// Writes the contents to the target
func unpackSingleFile(raw []byte, targetDirectory string, filename string) {
destPath := fmt.Sprintf("%s%c%s", targetDirectory, os.PathSeparator, filename)
// Check if the file already exists - we won't overwrite it then
_, fileInfoErr := os.Stat(destPath)
if os.IsExist(fileInfoErr) {
// File already exists, we don't need to write a thing
return
}
// Check if some funny stuff is going on
if strings.Contains(targetDirectory, "..") || strings.Contains(filename, "..") {
log.Printf("Skipping traversal filename: %s", filename)
return
}
// Check if the target directory already exists - otherwise we create it
dirOfFile := path.Dir(fmt.Sprintf("%s%c%s", targetDirectory, os.PathSeparator, filename))
_, dirInfoErr := os.Stat(dirOfFile)
if os.IsNotExist(dirInfoErr) {
// Create directories as required
mkdirErr := os.MkdirAll(dirOfFile, 0755)
if mkdirErr != nil {
log.Printf("Failed to create directory %s: %s", dirOfFile, mkdirErr)
return
}
}
// Write file
writeErr := ioutil.WriteFile(destPath, raw, 0644)
if writeErr != nil {
log.Printf("Unable to write to file %s: %s", destPath, writeErr)
}
2020-06-19 13:31:20 +00:00
}