Added fragment calculations (untested).
This commit is contained in:
+3
-3
@@ -45,7 +45,7 @@ type SuperblockFlags struct {
|
|||||||
//If true, ALL data is stored in sequential data blocks instead of utilizing fragments.
|
//If true, ALL data is stored in sequential data blocks instead of utilizing fragments.
|
||||||
NoFragments bool
|
NoFragments bool
|
||||||
//If true, the last block of data will always be stored as a fragment if it's less then the block size.
|
//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)
|
//If true, duplicate files are only stored once. (Currently unsupported)
|
||||||
RemoveDuplicates bool
|
RemoveDuplicates bool
|
||||||
//If true, the export table is populated. (Currently unsupported)
|
//If true, the export table is populated. (Currently unsupported)
|
||||||
@@ -73,7 +73,7 @@ func (s *superblock) GetFlags() SuperblockFlags {
|
|||||||
check: s.Flags&0x4 == 0x4,
|
check: s.Flags&0x4 == 0x4,
|
||||||
UncompressedFragments: s.Flags&0x8 == 0x8,
|
UncompressedFragments: s.Flags&0x8 == 0x8,
|
||||||
NoFragments: s.Flags&0x10 == 0x10,
|
NoFragments: s.Flags&0x10 == 0x10,
|
||||||
AlwaysFragments: s.Flags&0x20 == 0x20,
|
AlwaysFragment: s.Flags&0x20 == 0x20,
|
||||||
RemoveDuplicates: s.Flags&0x40 == 0x40,
|
RemoveDuplicates: s.Flags&0x40 == 0x40,
|
||||||
Exportable: s.Flags&0x80 == 0x80,
|
Exportable: s.Flags&0x80 == 0x80,
|
||||||
UncompressedXattr: s.Flags&0x100 == 0x100,
|
UncompressedXattr: s.Flags&0x100 == 0x100,
|
||||||
@@ -101,7 +101,7 @@ func (s *SuperblockFlags) ToUint() uint16 {
|
|||||||
if s.NoFragments {
|
if s.NoFragments {
|
||||||
out = out | 0x10
|
out = out | 0x10
|
||||||
}
|
}
|
||||||
if s.AlwaysFragments {
|
if s.AlwaysFragment {
|
||||||
out = out | 0x20
|
out = out | 0x20
|
||||||
}
|
}
|
||||||
if s.RemoveDuplicates {
|
if s.RemoveDuplicates {
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ import (
|
|||||||
type Writer struct {
|
type Writer struct {
|
||||||
compressor compression.Compressor
|
compressor compression.Compressor
|
||||||
structure map[string][]*fileHolder
|
structure map[string][]*fileHolder
|
||||||
symlinkTable map[string]string //[oldpath]newpath
|
symlinkTable map[string]string
|
||||||
folders []string
|
folders []string
|
||||||
uidGUIDTable []int
|
uidGUIDTable []int
|
||||||
|
frags []fragment
|
||||||
|
superblock superblock
|
||||||
compressionType int
|
compressionType int
|
||||||
//BlockSize is how large the data blocks are. Can be between 4096 (4KB) and 1048576 (1 MB).
|
//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.
|
//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
|
//Currently Duplicates, Exportable, UncompressedXattr, NoXattr values are ignored
|
||||||
Flags SuperblockFlags
|
Flags SuperblockFlags
|
||||||
allowErrors bool
|
allowErrors bool
|
||||||
|
|
||||||
//variables used when actually writing.
|
|
||||||
superblock superblock
|
|
||||||
frags []fragment
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//NewWriter creates a new with the default options (Gzip compression and allow errors)
|
//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 {
|
if compressionType == 3 {
|
||||||
return nil, errors.New("Lzo compression is not (currently) supported")
|
return nil, errors.New("Lzo compression is not (currently) supported")
|
||||||
}
|
}
|
||||||
return &Writer{
|
writer := &Writer{
|
||||||
structure: map[string][]*fileHolder{
|
structure: map[string][]*fileHolder{
|
||||||
"/": make([]*fileHolder, 0),
|
"/": make([]*fileHolder, 0),
|
||||||
},
|
},
|
||||||
@@ -64,7 +62,20 @@ func NewWriterWithOptions(compressionType int, allowErrors bool) (*Writer, error
|
|||||||
allowErrors: allowErrors,
|
allowErrors: allowErrors,
|
||||||
BlockSize: uint32(1048576),
|
BlockSize: uint32(1048576),
|
||||||
Flags: DefaultFlags,
|
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
|
//fileHolder holds the necessary information about a given file inside of a squashfs
|
||||||
@@ -80,6 +91,9 @@ type fileHolder struct {
|
|||||||
UID int
|
UID int
|
||||||
folder bool
|
folder bool
|
||||||
symlink bool
|
symlink bool
|
||||||
|
|
||||||
|
fragIndex int
|
||||||
|
fragOffset int
|
||||||
}
|
}
|
||||||
|
|
||||||
//AddFile attempts to add an os.File to the archive's root directory.
|
//AddFile attempts to add an os.File to the archive's root directory.
|
||||||
|
|||||||
@@ -16,6 +16,54 @@ func (f *fragment) SizeLeft() uint32 {
|
|||||||
|
|
||||||
func (f *fragment) AddFragment(fil *fileHolder) {
|
func (f *fragment) AddFragment(fil *fileHolder) {
|
||||||
//SizeLeft should already be checked
|
//SizeLeft should already be checked
|
||||||
|
fil.fragOffset = len(f.files)
|
||||||
f.files = append(f.files, fil)
|
f.files = append(f.files, fil)
|
||||||
f.sizes = append(f.sizes, fil.blockSizes[len(fil.blockSizes)-1])
|
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])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,17 +7,3 @@ func (w *Writer) countInodes() (out uint32) {
|
|||||||
}
|
}
|
||||||
return
|
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
@@ -24,6 +24,8 @@ func (w *Writer) fixFolders() error {
|
|||||||
//WriteTo attempts to write the archive to the given io.Writer.
|
//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)
|
//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).
|
//are added with full permission (777).
|
||||||
|
//
|
||||||
|
//Not working. Yet.
|
||||||
func (w *Writer) WriteTo(write io.Writer) (int64, error) {
|
func (w *Writer) WriteTo(write io.Writer) (int64, error) {
|
||||||
err := w.fixFolders()
|
err := w.fixFolders()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -37,6 +39,7 @@ func (w *Writer) WriteTo(write io.Writer) (int64, error) {
|
|||||||
w.Flags.RemoveDuplicates = false
|
w.Flags.RemoveDuplicates = false
|
||||||
w.Flags.Exportable = false
|
w.Flags.Exportable = false
|
||||||
w.Flags.NoXattr = true
|
w.Flags.NoXattr = true
|
||||||
|
w.calculateFragsAndBlockSizes()
|
||||||
w.superblock = superblock{
|
w.superblock = superblock{
|
||||||
Magic: magic,
|
Magic: magic,
|
||||||
InodeCount: w.countInodes(),
|
InodeCount: w.countInodes(),
|
||||||
@@ -49,6 +52,5 @@ func (w *Writer) WriteTo(write io.Writer) (int64, error) {
|
|||||||
MajorVersion: 4,
|
MajorVersion: 4,
|
||||||
MinorVersion: 0,
|
MinorVersion: 0,
|
||||||
}
|
}
|
||||||
_ = super
|
|
||||||
return 0, errors.New("I SAID DON'T")
|
return 0, errors.New("I SAID DON'T")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user