forked from forgejo/forgejo
Dump: add output format tar and output to stdout (#10376)
* Dump: Use mholt/archive/v3 to support tar including many compressions Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: Allow dump output to stdout Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: Fixed bug present since #6677 where SessionConfig.Provider is never "file" Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: never pack RepoRootPath, LFS.ContentPath and LogRootPath when they are below AppDataPath Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: also dump LFS (fixes #10058) Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Dump: never dump CustomPath if CustomPath is a subdir of or equal to AppDataPath (fixes #10365) Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * Use log.Info instead of fmt.Fprintf Signed-off-by: Philipp Homann <homann.philipp@googlemail.com> * import ordering * make fmt Co-authored-by: zeripath <art27@cantab.net> Co-authored-by: techknowlogick <techknowlogick@gitea.io> Co-authored-by: Matti R <matti@mdranta.net>
This commit is contained in:
parent
209b17c4e2
commit
684b7a999f
303 changed files with 301317 additions and 1183 deletions
306
vendor/github.com/nwaples/rardecode/archive.go
generated
vendored
Normal file
306
vendor/github.com/nwaples/rardecode/archive.go
generated
vendored
Normal file
|
@ -0,0 +1,306 @@
|
|||
package rardecode
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
maxSfxSize = 0x100000 // maximum number of bytes to read when searching for RAR signature
|
||||
sigPrefix = "Rar!\x1A\x07"
|
||||
|
||||
fileFmt15 = iota + 1 // Version 1.5 archive file format
|
||||
fileFmt50 // Version 5.0 archive file format
|
||||
)
|
||||
|
||||
var (
|
||||
errNoSig = errors.New("rardecode: RAR signature not found")
|
||||
errVerMismatch = errors.New("rardecode: volume version mistmatch")
|
||||
errCorruptHeader = errors.New("rardecode: corrupt block header")
|
||||
errCorruptFileHeader = errors.New("rardecode: corrupt file header")
|
||||
errBadHeaderCrc = errors.New("rardecode: bad header crc")
|
||||
errUnknownArc = errors.New("rardecode: unknown archive version")
|
||||
errUnknownDecoder = errors.New("rardecode: unknown decoder version")
|
||||
errUnsupportedDecoder = errors.New("rardecode: unsupported decoder version")
|
||||
errArchiveContinues = errors.New("rardecode: archive continues in next volume")
|
||||
errArchiveEnd = errors.New("rardecode: archive end reached")
|
||||
errDecoderOutOfData = errors.New("rardecode: decoder expected more data than is in packed file")
|
||||
|
||||
reDigits = regexp.MustCompile(`\d+`)
|
||||
)
|
||||
|
||||
type readBuf []byte
|
||||
|
||||
func (b *readBuf) byte() byte {
|
||||
v := (*b)[0]
|
||||
*b = (*b)[1:]
|
||||
return v
|
||||
}
|
||||
|
||||
func (b *readBuf) uint16() uint16 {
|
||||
v := uint16((*b)[0]) | uint16((*b)[1])<<8
|
||||
*b = (*b)[2:]
|
||||
return v
|
||||
}
|
||||
|
||||
func (b *readBuf) uint32() uint32 {
|
||||
v := uint32((*b)[0]) | uint32((*b)[1])<<8 | uint32((*b)[2])<<16 | uint32((*b)[3])<<24
|
||||
*b = (*b)[4:]
|
||||
return v
|
||||
}
|
||||
|
||||
func (b *readBuf) bytes(n int) []byte {
|
||||
v := (*b)[:n]
|
||||
*b = (*b)[n:]
|
||||
return v
|
||||
}
|
||||
|
||||
func (b *readBuf) uvarint() uint64 {
|
||||
var x uint64
|
||||
var s uint
|
||||
for i, n := range *b {
|
||||
if n < 0x80 {
|
||||
*b = (*b)[i+1:]
|
||||
return x | uint64(n)<<s
|
||||
}
|
||||
x |= uint64(n&0x7f) << s
|
||||
s += 7
|
||||
|
||||
}
|
||||
// if we run out of bytes, just return 0
|
||||
*b = (*b)[len(*b):]
|
||||
return 0
|
||||
}
|
||||
|
||||
// readFull wraps io.ReadFull to return io.ErrUnexpectedEOF instead
|
||||
// of io.EOF when 0 bytes are read.
|
||||
func readFull(r io.Reader, buf []byte) error {
|
||||
_, err := io.ReadFull(r, buf)
|
||||
if err == io.EOF {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// findSig searches for the RAR signature and version at the beginning of a file.
|
||||
// It searches no more than maxSfxSize bytes.
|
||||
func findSig(br *bufio.Reader) (int, error) {
|
||||
for n := 0; n <= maxSfxSize; {
|
||||
b, err := br.ReadSlice(sigPrefix[0])
|
||||
n += len(b)
|
||||
if err == bufio.ErrBufferFull {
|
||||
continue
|
||||
} else if err != nil {
|
||||
if err == io.EOF {
|
||||
err = errNoSig
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
b, err = br.Peek(len(sigPrefix[1:]) + 2)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = errNoSig
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
if !bytes.HasPrefix(b, []byte(sigPrefix[1:])) {
|
||||
continue
|
||||
}
|
||||
b = b[len(sigPrefix)-1:]
|
||||
|
||||
var ver int
|
||||
switch {
|
||||
case b[0] == 0:
|
||||
ver = fileFmt15
|
||||
case b[0] == 1 && b[1] == 0:
|
||||
ver = fileFmt50
|
||||
default:
|
||||
continue
|
||||
}
|
||||
_, _ = br.ReadSlice('\x00')
|
||||
|
||||
return ver, nil
|
||||
}
|
||||
return 0, errNoSig
|
||||
}
|
||||
|
||||
// volume extends a fileBlockReader to be used across multiple
|
||||
// files in a multi-volume archive
|
||||
type volume struct {
|
||||
fileBlockReader
|
||||
f *os.File // current file handle
|
||||
br *bufio.Reader // buffered reader for current volume file
|
||||
dir string // volume directory
|
||||
file string // current volume file
|
||||
num int // volume number
|
||||
old bool // uses old naming scheme
|
||||
}
|
||||
|
||||
// nextVolName updates name to the next filename in the archive.
|
||||
func (v *volume) nextVolName() {
|
||||
if v.num == 0 {
|
||||
// check file extensions
|
||||
i := strings.LastIndex(v.file, ".")
|
||||
if i < 0 {
|
||||
// no file extension, add one
|
||||
i = len(v.file)
|
||||
v.file += ".rar"
|
||||
} else {
|
||||
ext := strings.ToLower(v.file[i+1:])
|
||||
// replace with .rar for empty extensions & self extracting archives
|
||||
if ext == "" || ext == "exe" || ext == "sfx" {
|
||||
v.file = v.file[:i+1] + "rar"
|
||||
}
|
||||
}
|
||||
if a, ok := v.fileBlockReader.(*archive15); ok {
|
||||
v.old = a.old
|
||||
}
|
||||
// new naming scheme must have volume number in filename
|
||||
if !v.old && reDigits.FindStringIndex(v.file) == nil {
|
||||
v.old = true
|
||||
}
|
||||
// For old style naming if 2nd and 3rd character of file extension is not a digit replace
|
||||
// with "00" and ignore any trailing characters.
|
||||
if v.old && (len(v.file) < i+4 || v.file[i+2] < '0' || v.file[i+2] > '9' || v.file[i+3] < '0' || v.file[i+3] > '9') {
|
||||
v.file = v.file[:i+2] + "00"
|
||||
return
|
||||
}
|
||||
}
|
||||
// new style volume naming
|
||||
if !v.old {
|
||||
// find all numbers in volume name
|
||||
m := reDigits.FindAllStringIndex(v.file, -1)
|
||||
if l := len(m); l > 1 {
|
||||
// More than 1 match so assume name.part###of###.rar style.
|
||||
// Take the last 2 matches where the first is the volume number.
|
||||
m = m[l-2 : l]
|
||||
if strings.Contains(v.file[m[0][1]:m[1][0]], ".") || !strings.Contains(v.file[:m[0][0]], ".") {
|
||||
// Didn't match above style as volume had '.' between the two numbers or didnt have a '.'
|
||||
// before the first match. Use the second number as volume number.
|
||||
m = m[1:]
|
||||
}
|
||||
}
|
||||
// extract and increment volume number
|
||||
lo, hi := m[0][0], m[0][1]
|
||||
n, err := strconv.Atoi(v.file[lo:hi])
|
||||
if err != nil {
|
||||
n = 0
|
||||
} else {
|
||||
n++
|
||||
}
|
||||
// volume number must use at least the same number of characters as previous volume
|
||||
vol := fmt.Sprintf("%0"+fmt.Sprint(hi-lo)+"d", n)
|
||||
v.file = v.file[:lo] + vol + v.file[hi:]
|
||||
return
|
||||
}
|
||||
// old style volume naming
|
||||
i := strings.LastIndex(v.file, ".")
|
||||
// get file extension
|
||||
b := []byte(v.file[i+1:])
|
||||
// start incrementing volume number digits from rightmost
|
||||
for j := 2; j >= 0; j-- {
|
||||
if b[j] != '9' {
|
||||
b[j]++
|
||||
break
|
||||
}
|
||||
// digit overflow
|
||||
if j == 0 {
|
||||
// last character before '.'
|
||||
b[j] = 'A'
|
||||
} else {
|
||||
// set to '0' and loop to next character
|
||||
b[j] = '0'
|
||||
}
|
||||
}
|
||||
v.file = v.file[:i+1] + string(b)
|
||||
}
|
||||
|
||||
func (v *volume) next() (*fileBlockHeader, error) {
|
||||
for {
|
||||
var atEOF bool
|
||||
|
||||
h, err := v.fileBlockReader.next()
|
||||
switch err {
|
||||
case errArchiveContinues:
|
||||
case io.EOF:
|
||||
// Read all of volume without finding an end block. The only way
|
||||
// to tell if the archive continues is to try to open the next volume.
|
||||
atEOF = true
|
||||
default:
|
||||
return h, err
|
||||
}
|
||||
|
||||
v.f.Close()
|
||||
v.nextVolName()
|
||||
v.f, err = os.Open(v.dir + v.file) // Open next volume file
|
||||
if err != nil {
|
||||
if atEOF && os.IsNotExist(err) {
|
||||
// volume not found so assume that the archive has ended
|
||||
return nil, io.EOF
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
v.num++
|
||||
v.br.Reset(v.f)
|
||||
ver, err := findSig(v.br)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.version() != ver {
|
||||
return nil, errVerMismatch
|
||||
}
|
||||
v.reset() // reset encryption
|
||||
}
|
||||
}
|
||||
|
||||
func (v *volume) Close() error {
|
||||
// may be nil if os.Open fails in next()
|
||||
if v.f == nil {
|
||||
return nil
|
||||
}
|
||||
return v.f.Close()
|
||||
}
|
||||
|
||||
func openVolume(name, password string) (*volume, error) {
|
||||
var err error
|
||||
v := new(volume)
|
||||
v.dir, v.file = filepath.Split(name)
|
||||
v.f, err = os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v.br = bufio.NewReader(v.f)
|
||||
v.fileBlockReader, err = newFileBlockReader(v.br, password)
|
||||
if err != nil {
|
||||
v.f.Close()
|
||||
return nil, err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func newFileBlockReader(br *bufio.Reader, pass string) (fileBlockReader, error) {
|
||||
runes := []rune(pass)
|
||||
if len(runes) > maxPassword {
|
||||
pass = string(runes[:maxPassword])
|
||||
}
|
||||
ver, err := findSig(br)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch ver {
|
||||
case fileFmt15:
|
||||
return newArchive15(br, pass), nil
|
||||
case fileFmt50:
|
||||
return newArchive50(br, pass), nil
|
||||
}
|
||||
return nil, errUnknownArc
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue