Added fragment calculations (untested).

This commit is contained in:
Caleb Gardner
2021-02-25 03:17:20 -06:00
parent ae5ade0683
commit c9d451e24c
5 changed files with 75 additions and 25 deletions
+3 -3
View File
@@ -45,7 +45,7 @@ type SuperblockFlags struct {
//If true, ALL data is stored in sequential data blocks instead of utilizing fragments.
NoFragments bool
//If true, the last block of data will always be stored as a fragment if it's less then the block size.
AlwaysFragments bool
AlwaysFragment bool
//If true, duplicate files are only stored once. (Currently unsupported)
RemoveDuplicates bool
//If true, the export table is populated. (Currently unsupported)
@@ -73,7 +73,7 @@ func (s *superblock) GetFlags() SuperblockFlags {
check: s.Flags&0x4 == 0x4,
UncompressedFragments: s.Flags&0x8 == 0x8,
NoFragments: s.Flags&0x10 == 0x10,
AlwaysFragments: s.Flags&0x20 == 0x20,
AlwaysFragment: s.Flags&0x20 == 0x20,
RemoveDuplicates: s.Flags&0x40 == 0x40,
Exportable: s.Flags&0x80 == 0x80,
UncompressedXattr: s.Flags&0x100 == 0x100,
@@ -101,7 +101,7 @@ func (s *SuperblockFlags) ToUint() uint16 {
if s.NoFragments {
out = out | 0x10
}
if s.AlwaysFragments {
if s.AlwaysFragment {
out = out | 0x20
}
if s.RemoveDuplicates {
+21 -7
View File
@@ -19,9 +19,11 @@ import (
type Writer struct {
compressor compression.Compressor
structure map[string][]*fileHolder
symlinkTable map[string]string //[oldpath]newpath
symlinkTable map[string]string
folders []string
uidGUIDTable []int
frags []fragment
superblock superblock
compressionType int
//BlockSize is how large the data blocks are. Can be between 4096 (4KB) and 1048576 (1 MB).
//If BlockSize is not inside that range, it will be set to within the range before writing.
@@ -31,10 +33,6 @@ type Writer struct {
//Currently Duplicates, Exportable, UncompressedXattr, NoXattr values are ignored
Flags SuperblockFlags
allowErrors bool
//variables used when actually writing.
superblock superblock
frags []fragment
}
//NewWriter creates a new with the default options (Gzip compression and allow errors)
@@ -52,7 +50,7 @@ func NewWriterWithOptions(compressionType int, allowErrors bool) (*Writer, error
if compressionType == 3 {
return nil, errors.New("Lzo compression is not (currently) supported")
}
return &Writer{
writer := &Writer{
structure: map[string][]*fileHolder{
"/": make([]*fileHolder, 0),
},
@@ -64,7 +62,20 @@ func NewWriterWithOptions(compressionType int, allowErrors bool) (*Writer, error
allowErrors: allowErrors,
BlockSize: uint32(1048576),
Flags: DefaultFlags,
}, nil
}
switch compressionType {
case 1:
writer.compressor = &compression.Gzip{}
case 2:
writer.compressor = &compression.Lzma{}
case 4:
writer.compressor = &compression.Xz{}
case 5:
writer.compressor = &compression.Lz4{}
case 6:
writer.compressor = &compression.Zstd{}
}
return writer, nil
}
//fileHolder holds the necessary information about a given file inside of a squashfs
@@ -80,6 +91,9 @@ type fileHolder struct {
UID int
folder bool
symlink bool
fragIndex int
fragOffset int
}
//AddFile attempts to add an os.File to the archive's root directory.
+48
View File
@@ -16,6 +16,54 @@ func (f *fragment) SizeLeft() uint32 {
func (f *fragment) AddFragment(fil *fileHolder) {
//SizeLeft should already be checked
fil.fragOffset = len(f.files)
f.files = append(f.files, fil)
f.sizes = append(f.sizes, fil.blockSizes[len(fil.blockSizes)-1])
}
func (w *Writer) addToFragments(fil *fileHolder) {
fragSize := fil.blockSizes[len(fil.blockSizes)-1]
//only fragment if the final block is less then 80% of a full block or AlwaysFragment
if w.Flags.AlwaysFragment || fragSize < uint32(float32(w.BlockSize)*0.8) {
var possibleFrags []int
for i := range w.frags {
left := w.frags[i].SizeLeft()
if left == fragSize {
fil.fragIndex = i
w.frags[i].AddFragment(fil)
return
} else if left > fragSize {
possibleFrags = append(possibleFrags, i)
}
}
if len(possibleFrags) > 0 {
fil.fragIndex = possibleFrags[0]
} else {
fil.fragIndex = len(w.frags)
w.frags = append(w.frags, fragment{
w: w,
files: []*fileHolder{fil},
sizes: []uint32{fragSize},
})
}
}
}
func (w *Writer) calculateFragsAndBlockSizes() {
for _, files := range w.structure {
for i := range files {
files[i].fragIndex = -1
files[i].blockSizes = make([]uint32, files[i].size/uint64(w.BlockSize))
for j := range files[i].blockSizes {
files[i].blockSizes[j] = w.BlockSize
}
fragSize := uint32(files[i].size % uint64(w.BlockSize))
if fragSize > 0 {
files[i].blockSizes = append(files[i].blockSizes, fragSize)
if !w.Flags.NoFragments {
w.addToFragments(files[i])
}
}
}
}
}
-14
View File
@@ -7,17 +7,3 @@ func (w *Writer) countInodes() (out uint32) {
}
return
}
//intilialize the block sizes. These values will be overwritten with their compressed sizes later.
func (w *Writer) calculateBlockSizes(fil *fileHolder) {
tmp := fil.size
for {
if tmp < uint64(w.BlockSize) {
fil.blockSizes = append(fil.blockSizes, uint32(tmp))
break
}
tmp -= uint64(w.BlockSize)
fil.blockSizes = append(fil.blockSizes, w.BlockSize)
}
return
}
+3 -1
View File
@@ -24,6 +24,8 @@ func (w *Writer) fixFolders() error {
//WriteTo attempts to write the archive to the given io.Writer.
//Folder that aren't present (such as if you add a file at /folder/file, but not the folder /folder)
//are added with full permission (777).
//
//Not working. Yet.
func (w *Writer) WriteTo(write io.Writer) (int64, error) {
err := w.fixFolders()
if err != nil {
@@ -37,6 +39,7 @@ func (w *Writer) WriteTo(write io.Writer) (int64, error) {
w.Flags.RemoveDuplicates = false
w.Flags.Exportable = false
w.Flags.NoXattr = true
w.calculateFragsAndBlockSizes()
w.superblock = superblock{
Magic: magic,
InodeCount: w.countInodes(),
@@ -49,6 +52,5 @@ func (w *Writer) WriteTo(write io.Writer) (int64, error) {
MajorVersion: 4,
MinorVersion: 0,
}
_ = super
return 0, errors.New("I SAID DON'T")
}