Repository: diskfs/go-diskfs (go)

Issue:
SquashFS reading is not consistent with writing for large writing
When I use the following code to create a SquashFS image and try to write the contents of a file that exceeds the block size, I will find that when reading, I will read the contents of the super block, not just the file contents. If the length of the written data content is less than the block size, there will be no problem

### Example

```go
package main

import (
	"errors"
	"fmt"
	"io"
	"os"

	"github.com/diskfs/go-diskfs"
	"github.com/diskfs/go-diskfs/disk"
	"github.com/diskfs/go-diskfs/filesystem"
	"github.com/diskfs/go-diskfs/filesystem/squashfs"
)

func main() {
	CreateFilesystem := func(d *disk.Disk, spec disk.FilesystemSpec) (filesystem.FileSystem, error) {
		// find out where the partition starts and ends, or if it is the entire disk
		var (
			size, start int64
		)

		switch {
		case spec.Partition == 0:
			size = d.Size
			start = 0
		case d.Table == nil:
			return nil, fmt.Errorf("cannot create filesystem on a partition without a partition table")
		default:
			partitions := d.Table.GetPartitions()
			// API indexes from 1, but slice from 0
			part := spec.Partition - 1
			if spec.Partition > len(partitions) {
				return nil, fmt.Errorf("cannot create filesystem on partition %d greater than maximum partition %d", spec.Partition, len(partitions))
			}
			size = partitions[part].GetSize()
			start = partitions[part].GetStart()
		}

		switch spec.FSType {
		case filesystem.TypeSquashfs:
			return squashfs.Create(d.Backend, size, start, d.LogicalBlocksize)
		default:
			return nil, errors.New("unknown filesystem type requested")
		}
	}

	// Create squashfs image file
	var diskSize int64 = 10 * 1024 * 1024 // 10 MB
	initdataImagePath := "/root/tdx/development/test-squashfs/image-low"
	mydisk, err := diskfs.Create(initdataImagePath, diskSize, 4096)
	if err != nil {
		panic(err)
	}

	fspec := disk.FilesystemSpec{Partition: 0, FSType: filesystem.TypeSquashfs, VolumeLabel: "label"}
	fs, err := CreateFilesystem(mydisk, fspec)
	if err != nil {
		panic(err)
	}

	rw, err := fs.OpenFile("/test", os.O_CREATE|os.O_RDWR)
	if err != nil {
		panic(err)
	}

	_, err = rw.Write([]byte("dmVyc2PSAnJycKW3Rva2VuX2NvbmZpZ3NdCgpbdG9rZW5fY29uZmlncy5jb2NvX2FzXQp1cmwgPSAiaHR0cDovLzguMjE4LjIuMjIzOjgwMDAiCgpbdG9rZW5fY29uZmlncy5rYnNdCnVybCA9ICJodHRwczovLzguMjE4LjIuMjIzOjgwODAiCgpbZXZlbnRsb2dfY29uZmlnXQoKZXZlbnRsb2dfYWxnb3JpdGhtID0gInNoYTM4NCIKaW5pdF9wY3IgPSAxNwplbmFibGVfZXZlbnRsb2cgPSBmYWxzZQonJycKCiJjZGgudG9tbCIgPSAnJycKIyBUaGUgdHRycGMgc29jayBvZiBDREggdGhhdCBpcyB1c2VkIHRvIGxpc3RlbiB0byB0aGUgcmVxdWVzdHMKc29ja2V0ID0gInVuaXg6Ly8vcnVuL2NvbmZpZGVudGlhbC1jb250YWluZXJzL2NkaC5zb2NrIgoKIyBLQkMgcmVsYXRlZCBjb25maWdzLgpba2JjXQojIFJlcXVpcmVkLiBUaGUgS0JDIG5hbWUuIEl0IGNvdWxkIGJlIGBjY19rYmNgLCBgb25saW5lX3Nldl9rYmNgIG9yCiMgYG9mZmxpbmVfZnNfa2JjYC4gQWxsIHRoZSBpdGVtcyB1bmRlciBgW2NyZWRlbnRpYWxzXWAgd2lsbCBiZQojIHJldHJpZXZlZCB1c2luZyB0aGUga2JjLgpuYW1lID0gImNjX2tiYyIKCiMgUmVxdWlyZWQuIFRoZSBVUkwgb2YgS0JTLiBJZiBgbmFtZWAgaXMgZWl0aGVyIGBjY19rYmNgIG9yCiMgYG9ubGluZV9zZXZfa2JjYCwgdGhpcyBVUkwgd2lsbCBiZSB1c2VkIHRvIGNvbm5lY3QgdG8gdGhlCiMgQ29Db0tCUyAoZm9yIGNjX2tiYykgb3IgU2ltcGxlLUtCUyAoZm9yIG9ubGluZV9zZXZfa2JjKS4gSWYKIyBgbmFtZWAgaXMgYG9mZmxpbmVfZnNfa2JjYCwgVGhpcyBVUkwgd2lsbCBiZSBpZ25vcmVkLgp1cmwgPSAiaHR0cHM6Ly84LjIxOC4yLjIyMzo4MDgwIgoKIyBPcHRpb25hbC4gVGhlIHB1YmxpYyBrZXkgY2VydCBvZiBLQlMuIElmIG5vdCBnaXZlbiwgQ0RIIHdpbGwKIyB0cnkgdG8gdXNlIEhUVFAgdG8gY29ubmVjdCB0aGUgc2VydmVyLgojIGtic19jZXJ0ID0gIiIKCiMgY3JlZGVudGlhbHMgYXJlIGl0ZW1zIHRoYXQgd2lsbCBiZSByZXRyaWV2ZWQgZnJvbSBLQlMgd2hlbiBDREgKIyBpcyBsYXVuY2hlZC4gYHJlc291cmNlX3VyaWAgcmVmZXJzIHRvIHRoZSBLQlMgcmVzb3VyY2UgdXJpIGFuZAojIGBwYXRoYCBpcyB3aGVyZSB0byBwbGFjZSB0aGUgZmlsZS4KIyBgcGF0aGAgbXVzdCBiZSB3aXRoIHByZWZpeCBgL3J1bi9jb25maWRlbnRpYWwtY29udGFpbmVycy9jZGhgLAojIG9yIGl0IHdpbGwgYmUgYmxvY2tlZCBieSBDREguCiMgW1tjcmVkZW50aWFsc11dCiMgcGF0aCA9ICIvcnVuL2NvbmZpZGVudGlhbC1jb250YWluZXJzL2NkaC9rbXMtY3JlZGVudGlhbC9hbGl5dW4vZWNzUmFtUm9sZS5qc29uIgojIHJlc291cmNlX3VyaSA9ICJrYnM6Ly8vZGVmYXVsdC9hbGl5dW4vZWNzX3JhbV9yb2xlIgoKIyBbW2NyZWRlbnRpYWxzXV0KIyBwYXRoID0gIi9ydW4vY29uZmlkZW50aWFsLWNvbnRhaW5lcnMvY2RoL3Rlc3QvZmlsZSIKIyByZXNvdXJjZV91cmkgPSAia2JzOi8vL2RlZmF1bHQvdGVzdC9maWxlIgoKW2ltYWdlXQoKIyBUaGUgbWF4aW11bSBudW1iZXIgb2YgbGF5ZXJzIGRvd25sb2FkZWQgY29uY3VycmVudGx5IHdoZW4KIyBwdWxsaW5nIG9uZSBzcGVjaWZpYyBpbWFnZS4KIwojIFRoaXMgZGVmYXVsdHMgdG8gMy4KbWF4X2NvbmN1cnJlbnRfbGF5ZXJfZG93bmxvYWRzX3Blcl9pbWFnZSA9IDMKCiMgU2lnc3RvcmUgY29uZmlnIGZpbGUgVVJJIGZvciBzaW1wbGUgc2lnbmluZyBzY2hlbWUuCiMKIyBXaGVuIGBpbWFnZV9zZWN1cml0eV9wb2xpY3lfdXJpYCBpcyBzZXQgYW5kIGBTaW1wbGVTaWduaW5nYCAoc2lnbmVkQnkpIGlzCiMgdXNlZCBpbiB0aGUgcG9saWN5LCB0aGUgc2lnbmF0dXJlcyBvZiB0aGUgaW1hZ2VzIHdvdWxkIGJlIHVzZWQgZm9yIGltYWdlCiMgc2lnbmF0dXJlIHZhbGlkYXRpb24uIFRoaXMgcG9saWN5IHdpbGwgcmVjb3JkIHdoZXJlIHRoZSBzaWduYXR1cmVzIGlzLgojCiMgTm93IGl0IHN1cHBvcnRzIHR3byBkaWZmZXJlbnQgZm9ybXM6CiMgLSBgS0JTIFVSSWA6IHRoZSBzaWdzdG9yZSBjb25maWcgZmlsZSB3aWxsIGJlIGZldGNoZWQgZnJvbSBLQlMsCiMgZS5nLiBga2JzOi8vL2RlZmF1bHQvc2lnc3RvcmUtY29uZmlnL3Rlc3RgLgojIC0gYExvY2FsIFBhdGhgOiB0aGUgc2lnc3RvcmUgY29uZmlnIGZpbGUgd2lsbCBiZSBmZXRjaGVkIGZyb20gc29tZXdoZXJlIGxvY2FsbHksCiMgZS5nLiBgZmlsZTovLy9ldGMvc2ltcGxlLXNpZ25pbmcueWFtbGAuCiMKIyBCeSBkZWZhdWx0IHRoaXMgdmFsdWUgaXMgbm90IHNldC4Kc2lnc3RvcmVfY29uZmlnX3VyaSA9ICJrYnM6Ly8vZGVmYXVsdC9zaWdzdG9yZS1jb25maWcvdGVzdCIKCiMgSWYgYW55IGltYWdlIHNlY3VyaXR5IHBvbGljeSB3b3VsZCBiZSB1c2VkIHRvIGNvbnRyb2wgdGhlIGltYWdlIHB1bGxpbmcKIyBsaWtlIHNpZ25hdHVyZSB2ZXJpZmljYXRpb24sIHRoaXMgZmllbGQgaXMgdXNlZCB0byBzZXQgdGhlIFVSSSBvZiB0aGUKIyBwb2xpY3kgZmlsZS4KIwojIE5vdyBpdCBzdXBwb3J0cyB0d28gZGlmZmVyZW50IGZvcm1zOgojIC0gYEtCUyBVUklgOiB0aGUgaWFtZ2Ugc2VjdXJpdHkgcG9saWN5IHdpbGwgYmUgZmV0Y2hlZCBmcm9tIEtCUy4KIyAtIGBMb2NhbCBQYXRoYDogdGhlIHNlY3VyaXR5IHBvbGljeSB3aWxsIGJlIGZldGNoZWQgZnJvbSBzb21ld2hlcmUgbG9jYWxseS4KIyBlLmcuIGBmaWxlOi8vL2V0Yy9pbWFnZS1wb2xpY3kuanNvbmAuCiMKIyBUaGUgcG9saWN5IGZvbGxvd3MgdGhlIGZvcm1hdCBvZgojIDxodHRwczovL2dpdGh1Yi5jb20vY29udGFpbmVycy9pbWFnZS9ibG9iL21haW4vZG9jcy9jb250YWluZXJzLXBvbGljeS5qc29uLjUubWQ+LgojCiMgQXQgdGhlIHNhbWUgdGltZSwgc29tZSBlbmhlbmNlbWVudHMgYmFzZWQgb24gQ29DbyBpcyB1c2VkLCB0aGF0IGlzIHRoZQojIGBrZXlQYXRoYCBmaWVsZCBjYW4gYmUgZmlsbGVkIHdpdGggYSBLQlMgVVJJIGxpa2UgYGticzovLy9kZWZhdWx0L2tleS8xYAojCiMgQnkgZGVmYXVsdCB0aGlzIHZhbHVlIGlzIG5vdCBzZXQuCmltYWdlX3NlY3VyaXR5X3BvbGljeV91cmkgPSAia2JzOi8vL2RlZmF1bHQvc2VjdXJpdHktcG9saWN5L3Rlc3QiCgojIElmIGFueSBjcmVkZW50aWFsIGF1dGggKEJhc2UpIHdvdWxkIGJlIHVzZWQgdG8gY29ubmVjdCB0byBkb3dubG9hZAojIGltYWdlIGZyb20gcHJpdmF0ZSByZWdpc3RyeSwgdGhpcyBmaWVsZCBpcyB1c2VkIHRvIHNldCB0aGUgVVJJIG9mIHRoZQojIGNyZWRlbnRpYWwgZmlsZS4KIwojIE5vdyBpdCBzdXBwb3J0cyB0d28gZGlmZmVyZW50IGZvcm1zOgojIC0gYEtCUyBVUklgOiB0aGUgcmVnaXN0cnkgYXV0aCB3aWxsIGJlIGZldGNoZWQgZnJvbSBLQlMsCiMgZS5nLiBga2JzOi8vL2RlZmF1bHQvY3JlZGVudGlhbC90ZXN0YC4KIyAtIGBMb2NhbCBQYXRoYDogdGhlIHJlZ2lzdHJ5IGF1dGggd2lsbCBiZSBmZXRjaGVkIGZyb20gc29tZXdoZXJlIGxvY2FsbHksCiMgZS5nLiBgZmlsZTovLy9ldGMvaW1hZ2UtcmVnaXN0cnktYXV0aC5qc29uYC4KIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0LgphdXRoZW50aWNhdGVkX3JlZ2lzdHJ5X2NyZWRlbnRpYWxzX3VyaSA9ICJrYnM6Ly8vZGVmYXVsdC9jcmVkZW50aWFsL3Rlc3QiCgojIFByb3h5IHRoYXQgd2lsbCBiZSB1c2VkIHRvIHB1bGwgaW1hZ2UKIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0LgojIGltYWdlX3B1bGxfcHJveHkgPSAiaHR0cDovLzEyNy4wLjAuMTo1NDMyIgoKIyBObyBwcm94eSBlbnYgdGhhdCB3aWxsIGJlIHVzZWQgdG8gcHVsbCBpbWFnZS4KIwojIFRoaXMgd2lsbCBlbnN1cmUgdGhhdCB3aGVuIHdlIGFjY2VzcyB0aGUgaW1hZ2UgcmVnaXN0cnkgd2l0aCBzcGVjaWZpZWQKIyBJUHMsIHRoZSBgaW1hZ2VfcHVsbF9wcm94eWAgd2lsbCBub3QgYmUgdXNlZC4KIwojIElmIGBpbWFnZV9wdWxsX3Byb3h5YCBpcyBub3Qgc2V0LCB0aGlzIGZpZWxkIHdpbGwgZG8gbm90aGluZy4KIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0Lgpza2lwX3Byb3h5X2lwcyA9ICIxOTIuMTY4LjAuMSxsb2NhbGhvc3QiCgojIFRvIHN1cHBvcnQgcmVnaXN0cmllcyB3aXRoIHNlbGYgc2lnbmVkIGNlcnRzLiBUaGlzIGNvbmZpZyBpdGVtCiMgaXMgdXNlZCB0byBhZGQgZXh0cmEgdHJ1c3RlZCByb290IGNlcnRpZmljYXRpb25zLiBUaGUgY2VydGlmaWNhdGVzCiMgbXVzdCBiZSBlbmNvZGVkIGJ5IFBFTS4KIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0LgpleHRyYV9yb290X2NlcnRpZmljYXRlcyA9IFtdCgojIFRoZSBwYXRoIHRvIHN0b3JlIHRoZSBwdWxsZWQgaW1hZ2UgbGF5ZXIgZGF0YS4KIwojIFRoaXMgdmFsdWUgZGVmYXVsdHMgdG8gYC9ydW4vaW1hZ2UtcnMvYC4Kd29ya19kaXIgPSAiL3J1bi9pbWFnZS1ycyIKJycnCgoicG9saWN5LnJlZ28iID0gJycnCiMgQ29weXJpZ2h0IChjKSAyMDIzIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbgojCiMgU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjAKIwoKcGFja2FnZSBhZ2VudF9wb2xpY3kKCmRlZmF1bHQgQWRkQVJQTmVpZ2hib3JzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgQWRkU3dhcFJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IENsb3NlU3RkaW5SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBDb3B5RmlsZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IENyZWF0ZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IENyZWF0ZVNhbmRib3hSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBEZXN0cm95U2FuZGJveFJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IEV4ZWNQcm9jZXNzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgR2V0TWV0cmljc1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IEdldE9PTUV2ZW50UmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgR3Vlc3REZXRhaWxzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgTGlzdEludGVyZmFjZXNSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBMaXN0Um91dGVzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgTWVtSG90cGx1Z0J5UHJvYmVSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBPbmxpbmVDUFVNZW1SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBQYXVzZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFB1bGxJbWFnZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFJlYWRTdHJlYW1SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZW1vdmVDb250YWluZXJSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZW1vdmVTdGFsZVZpcnRpb2ZzU2hhcmVNb3VudHNSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZXNlZWRSYW5kb21EZXZSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZXN1bWVDb250YWluZXJSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBTZXRHdWVzdERhdGVUaW1lUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU2V0UG9saWN5UmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU2lnbmFsUHJvY2Vzc1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFN0YXJ0Q29udGFpbmVyUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU3RhcnRUcmFjaW5nUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU3RhdHNDb250YWluZXJSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBTdG9wVHJhY2luZ1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFR0eVdpblJlc2l6ZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZUVwaGVtZXJhbE1vdW50c1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZUludGVyZmFjZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZVJvdXRlc1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFdhaXRQcm9jZXNzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgV3JpdGVTdHJlYW1SZXF1ZXN0IDo9IHRydWUKJycnCglvbiA9ICIwLjEuMCIKYWxnb3JpdGhtID0gInNoYTI1NiIKW2RhdGFdCgoiYWEudG9tbCIg"))
	// _, err = rw.Write([]byte("123"))
	if err != nil {
		panic(err)
	}

	sqs, ok := fs.(*squashfs.FileSystem)
	if !ok {
		panic("not a squashfs filesystem")
	}
	err = sqs.Finalize(squashfs.FinalizeOptions{
		NoCompressInodes:    true,
		NoCompressData:      true,
		NoCompressFragments: true,
	})
	if err != nil {
		panic(err)
	}

	fmt.Println("Reading...")
	disk, err := diskfs.Open(initdataImagePath, diskfs.WithSectorSize(4096))
	if err != nil {
		panic(err)
	}
	fsr, err := disk.GetFilesystem(0) // assuming it is the whole disk, so partition = 0
	if err != nil {
		panic(err)
	}

	f, err := fsr.OpenFile("/test", os.O_RDONLY)
	if err != nil {
		panic(err)
	}

	buffer, err := io.ReadAll(f)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(buffer))
}

```

### Result

```
Reading...
hsqs�R�g
        �����������V���dmVyc2PSAnJycKW3Rva2VuX2NvbmZpZ3NdCgpbdG9rZW5fY29uZmlncy5jb2NvX2FzXQp1cmwgPSAiaHR0cDovLzguMjE4LjIuMjIzOjgwMDAiCgpbdG9rZW5fY29uZmlncy5rYnNdCnVybCA9ICJodHRwczovLzguMjE4LjIuMjIzOjgwODAiCgpbZXZlbnRsb2dfY29uZmlnXQoKZXZlbnRsb2dfYWxnb3JpdGhtID0gInNoYTM4NCIKaW5pdF9wY3IgPSAxNwplbmFibGVfZXZlbnRsb2cgPSBmYWxzZQonJycKCiJjZGgudG9tbCIgPSAnJycKIyBUaGUgdHRycGMgc29jayBvZiBDREggdGhhdCBpcyB1c2VkIHRvIGxpc3RlbiB0byB0aGUgcmVxdWVzdHMKc29ja2V0ID0gInVuaXg6Ly8vcnVuL2NvbmZpZGVudGlhbC1jb250YWluZXJzL2NkaC5zb2NrIgoKIyBLQkMgcmVsYXRlZCBjb25maWdzLgpba2JjXQojIFJlcXVpcmVkLiBUaGUgS0JDIG5hbWUuIEl0IGNvdWxkIGJlIGBjY19rYmNgLCBgb25saW5lX3Nldl9rYmNgIG9yCiMgYG9mZmxpbmVfZnNfa2JjYC4gQWxsIHRoZSBpdGVtcyB1bmRlciBgW2NyZWRlbnRpYWxzXWAgd2lsbCBiZQojIHJldHJpZXZlZCB1c2luZyB0aGUga2JjLgpuYW1lID0gImNjX2tiYyIKCiMgUmVxdWlyZWQuIFRoZSBVUkwgb2YgS0JTLiBJZiBgbmFtZWAgaXMgZWl0aGVyIGBjY19rYmNgIG9yCiMgYG9ubGluZV9zZXZfa2JjYCwgdGhpcyBVUkwgd2lsbCBiZSB1c2VkIHRvIGNvbm5lY3QgdG8gdGhlCiMgQ29Db0tCUyAoZm9yIGNjX2tiYykgb3IgU2ltcGxlLUtCUyAoZm9yIG9ubGluZV9zZXZfa2JjKS4gSWYKIyBgbmFtZWAgaXMgYG9mZmxpbmVfZnNfa2JjYCwgVGhpcyBVUkwgd2lsbCBiZSBpZ25vcmVkLgp1cmwgPSAiaHR0cHM6Ly84LjIxOC4yLjIyMzo4MDgwIgoKIyBPcHRpb25hbC4gVGhlIHB1YmxpYyBrZXkgY2VydCBvZiBLQlMuIElmIG5vdCBnaXZlbiwgQ0RIIHdpbGwKIyB0cnkgdG8gdXNlIEhUVFAgdG8gY29ubmVjdCB0aGUgc2VydmVyLgojIGtic19jZXJ0ID0gIiIKCiMgY3JlZGVudGlhbHMgYXJlIGl0ZW1zIHRoYXQgd2lsbCBiZSByZXRyaWV2ZWQgZnJvbSBLQlMgd2hlbiBDREgKIyBpcyBsYXVuY2hlZC4gYHJlc291cmNlX3VyaWAgcmVmZXJzIHRvIHRoZSBLQlMgcmVzb3VyY2UgdXJpIGFuZAojIGBwYXRoYCBpcyB3aGVyZSB0byBwbGFjZSB0aGUgZmlsZS4KIyBgcGF0aGAgbXVzdCBiZSB3aXRoIHByZWZpeCBgL3J1bi9jb25maWRlbnRpYWwtY29udGFpbmVycy9jZGhgLAojIG9yIGl0IHdpbGwgYmUgYmxvY2tlZCBieSBDREguCiMgW1tjcmVkZW50aWFsc11dCiMgcGF0aCA9ICIvcnVuL2NvbmZpZGVudGlhbC1jb250YWluZXJzL2NkaC9rbXMtY3JlZGVudGlhbC9hbGl5dW4vZWNzUmFtUm9sZS5qc29uIgojIHJlc291cmNlX3VyaSA9ICJrYnM6Ly8vZGVmYXVsdC9hbGl5dW4vZWNzX3JhbV9yb2xlIgoKIyBbW2NyZWRlbnRpYWxzXV0KIyBwYXRoID0gIi9ydW4vY29uZmlkZW50aWFsLWNvbnRhaW5lcnMvY2RoL3Rlc3QvZmlsZSIKIyByZXNvdXJjZV91cmkgPSAia2JzOi8vL2RlZmF1bHQvdGVzdC9maWxlIgoKW2ltYWdlXQoKIyBUaGUgbWF4aW11bSBudW1iZXIgb2YgbGF5ZXJzIGRvd25sb2FkZWQgY29uY3VycmVudGx5IHdoZW4KIyBwdWxsaW5nIG9uZSBzcGVjaWZpYyBpbWFnZS4KIwojIFRoaXMgZGVmYXVsdHMgdG8gMy4KbWF4X2NvbmN1cnJlbnRfbGF5ZXJfZG93bmxvYWRzX3Blcl9pbWFnZSA9IDMKCiMgU2lnc3RvcmUgY29uZmlnIGZpbGUgVVJJIGZvciBzaW1wbGUgc2lnbmluZyBzY2hlbWUuCiMKIyBXaGVuIGBpbWFnZV9zZWN1cml0eV9wb2xpY3lfdXJpYCBpcyBzZXQgYW5kIGBTaW1wbGVTaWduaW5nYCAoc2lnbmVkQnkpIGlzCiMgdXNlZCBpbiB0aGUgcG9saWN5LCB0aGUgc2lnbmF0dXJlcyBvZiB0aGUgaW1hZ2VzIHdvdWxkIGJlIHVzZWQgZm9yIGltYWdlCiMgc2lnbmF0dXJlIHZhbGlkYXRpb24uIFRoaXMgcG9saWN5IHdpbGwgcmVjb3JkIHdoZXJlIHRoZSBzaWduYXR1cmVzIGlzLgojCiMgTm93IGl0IHN1cHBvcnRzIHR3byBkaWZmZXJlbnQgZm9ybXM6CiMgLSBgS0JTIFVSSWA6IHRoZSBzaWdzdG9yZSBjb25maWcgZmlsZSB3aWxsIGJlIGZldGNoZWQgZnJvbSBLQlMsCiMgZS5nLiBga2JzOi8vL2RlZmF1bHQvc2lnc3RvcmUtY29uZmlnL3Rlc3RgLgojIC0gYExvY2FsIFBhdGhgOiB0aGUgc2lnc3RvcmUgY29uZmlnIGZpbGUgd2lsbCBiZSBmZXRjaGVkIGZyb20gc29tZXdoZXJlIGxvY2FsbHksCiMgZS5nLiBgZmlsZTovLy9ldGMvc2ltcGxlLXNpZ25pbmcueWFtbGAuCiMKIyBCeSBkZWZhdWx0IHRoaXMgdmFsdWUgaXMgbm90IHNldC4Kc2lnc3RvcmVfY29uZmlnX3VyaSA9ICJrYnM6Ly8vZGVmYXVsdC9zaWdzdG9yZS1jb25maWcvdGVzdCIKCiMgSWYgYW55IGltYWdlIHNlY3VyaXR5IHBvbGljeSB3b3VsZCBiZSB1c2VkIHRvIGNvbnRyb2wgdGhlIGltYWdlIHB1bGxpbmcKIyBsaWtlIHNpZ25hdHVyZSB2ZXJpZmljYXRpb24sIHRoaXMgZmllbGQgaXMgdXNlZCB0byBzZXQgdGhlIFVSSSBvZiB0aGUKIyBwb2xpY3kgZmlsZS4KIwojIE5vdyBpdCBzdXBwb3J0cyB0d28gZGlmZmVyZW50IGZvcm1zOgojIC0gYEtCUyBVUklgOiB0aGUgaWFtZ2Ugc2VjdXJpdHkgcG9saWN5IHdpbGwgYmUgZmV0Y2hlZCBmcm9tIEtCUy4KIyAtIGBMb2NhbCBQYXRoYDogdGhlIHNlY3VyaXR5IHBvbGljeSB3aWxsIGJlIGZldGNoZWQgZnJvbSBzb21ld2hlcmUgbG9jYWxseS4KIyBlLmcuIGBmaWxlOi8vL2V0Yy9pbWFnZS1wb2xpY3kuanNvbmAuCiMKIyBUaGUgcG9saWN5IGZvbGxvd3MgdGhlIGZvcm1hdCBvZgojIDxodHRwczovL2dpdGh1Yi5jb20vY29udGFpbmVycy9pbWFnZS9ibG9iL21haW4vZG9jcy9jb250YWluZXJzLXBvbGljeS5qc29uLjUubWQ+LgojCiMgQXQgdGhlIHNhbWUgdGltZSwgc29tZSBlbmhlbmNlbWVudHMgYmFzZWQgb24gQ29DbyBpcyB1c2VkLCB0aGF0IGlzIHRoZQojIGBrZXlQYXRoYCBmaWVsZCBjYW4gYmUgZmlsbGVkIHdpdGggYSBLQlMgVVJJIGxpa2UgYGticzovLy9kZWZhdWx0L2tleS8xYAojCiMgQnkgZGVmYXVsdCJpdHktcG9saWN5L3Rlc3QiCgojIElmIGFueSBjcmVkZW50aWFsIGF1dGggKEJhc2UpIHdvdWxkIGJlIHVzZWQgdG8gY29ubmVjdCB0byBkb3dubG9hZAojIGltYWdlIGZyb20gcHJpdmF0ZSByZWdpc3RyeSwgdGhpcyBmaWVsZCBpcyB1c2VkIHRvIHNldCB0aGUgVVJJIG9mIHRoZQojIGNyZWRlbnRpYWwgZmlsZS4KIwojIE5vdyBpdCBzdXBwb3J0cyB0d28gZGlmZmVyZW50IGZvcm1zOgojIC0gYEtCUyBVUklgOiB0aGUgcmVnaXN0cnkgYXV0aCB3aWxsIGJlIGZldGNoZWQgZnJvbSBLQlMsCiMgZS5nLiBga2JzOi8vL2RlZmF1bHQvY3JlZGVudGlhbC90ZXN0YC4KIyAtIGBMb2NhbCBQYXRoYDogdGhlIHJlZ2lzdHJ5IGF1dGggd2lsbCBiZSBmZXRjaGVkIGZyb20gc29tZXdoZXJlIGxvY2FsbHksCiMgZS5nLiBgZmlsZTovLy9ldGMvaW1hZ2UtcmVnaXN0cnktYXV0aC5qc29uYC4KIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0LgphdXRoZW50aWNhdGVkX3JlZ2lzdHJ5X2NyZWRlbnRpYWxzX3VyaSA9ICJrYnM6Ly8vZGVmYXVsdC9jcmVkZW50aWFsL3Rlc3QiCgojIFByb3h5IHRoYXQgd2lsbCBiZSB1c2VkIHRvIHB1bGwgaW1hZ2UKIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0LgojIGltYWdlX3B1bGxfcHJveHkgPSAiaHR0cDovLzEyNy4wLjAuMTo1NDMyIgoKIyBObyBwcm94eSBlbnYgdGhhdCB3aWxsIGJlIHVzZWQgdG8gcHVsbCBpbWFnZS4KIwojIFRoaXMgd2lsbCBlbnN1cmUgdGhhdCB3aGVuIHdlIGFjY2VzcyB0aGUgaW1hZ2UgcmVnaXN0cnkgd2l0aCBzcGVjaWZpZWQKIyBJUHMsIHRoZSBgaW1hZ2VfcHVsbF9wcm94eWAgd2lsbCBub3QgYmUgdXNlZC4KIwojIElmIGBpbWFnZV9wdWxsX3Byb3h5YCBpcyBub3Qgc2V0LCB0aGlzIGZpZWxkIHdpbGwgZG8gbm90aGluZy4KIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0Lgpza2lwX3Byb3h5X2lwcyA9ICIxOTIuMTY4LjAuMSxsb2NhbGhvc3QiCgojIFRvIHN1cHBvcnQgcmVnaXN0cmllcyB3aXRoIHNlbGYgc2lnbmVkIGNlcnRzLiBUaGlzIGNvbmZpZyBpdGVtCiMgaXMgdXNlZCB0byBhZGQgZXh0cmEgdHJ1c3RlZCByb290IGNlcnRpZmljYXRpb25zLiBUaGUgY2VydGlmaWNhdGVzCiMgbXVzdCBiZSBlbmNvZGVkIGJ5IFBFTS4KIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0LgpleHRyYV9yb290X2NlcnRpZmljYXRlcyA9IFtdCgojIFRoZSBwYXRoIHRvIHN0b3JlIHRoZSBwdWxsZWQgaW1hZ2UgbGF5ZXIgZGF0YS4KIwojIFRoaXMgdmFsdWUgZGVmYXVsdHMgdG8gYC9ydW4vaW1hZ2UtcnMvYC4Kd29ya19kaXIgPSAiL3J1bi9pbWFnZS1ycyIKJycnCgoicG9saWN5LnJlZ28iID0gJycnCiMgQ29weXJpZ2h0IChjKSAyMDIzIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbgojCiMgU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjAKIwoKcGFja2FnZSBhZ2VudF9wb2xpY3kKCmRlZmF1bHQgQWRkQVJQTmVpZ2hib3JzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgQWRkU3dhcFJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IENsb3NlU3RkaW5SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBDb3B5RmlsZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IENyZWF0ZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IENyZWF0ZVNhbmRib3hSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBEZXN0cm95U2FuZGJveFJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IEV4ZWNQcm9jZXNzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgR2V0TWV0cmljc1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IEdldE9PTUV2ZW50UmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgR3Vlc3REZXRhaWxzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgTGlzdEludGVyZmFjZXNSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBMaXN0Um91dGVzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgTWVtSG90cGx1Z0J5UHJvYmVSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBPbmxpbmVDUFVNZW1SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBQYXVzZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFB1bGxJbWFnZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFJlYWRTdHJlYW1SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZW1vdmVDb250YWluZXJSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZW1vdmVTdGFsZVZpcnRpb2ZzU2hhcmVNb3VudHNSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZXNlZWRSYW5kb21EZXZSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZXN1bWVDb250YWluZXJSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBTZXRHdWVzdERhdGVUaW1lUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU2V0UG9saWN5UmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU2lnbmFsUHJvY2Vzc1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFN0YXJ0Q29udGFpbmVyUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU3RhcnRUcmFjaW5nUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU3RhdHNDb250YWluZXJSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBTdG9wVHJhY2luZ1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFR0eVdpblJlc2l6ZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZUVwaGVtZXJhbE1vdW50c1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZUludGVyZmFjZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZVJvdXRlc1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFdhaXRQcm9jZXNzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgV3JpdGVTdHJlYW1SZXF1ZXN0IDo9IHRydWUKJycnCglvbiA9ICIwLjEuMCIKYWxnb3JpdGhtID0gInNoYTI1NiIKW2RhdGFdCgoiYWEudG9tbCIg
```

### Expected
```
dmVyc2PSAnJycKW3Rva2VuX2NvbmZpZ3NdCgpbdG9rZW5fY29uZmlncy5jb2NvX2FzXQp1cmwgPSAiaHR0cDovLzguMjE4LjIuMjIzOjgwMDAiCgpbdG9rZW5fY29uZmlncy5rYnNdCnVybCA9ICJodHRwczovLzguMjE4LjIuMjIzOjgwODAiCgpbZXZlbnRsb2dfY29uZmlnXQoKZXZlbnRsb2dfYWxnb3JpdGhtID0gInNoYTM4NCIKaW5pdF9wY3IgPSAxNwplbmFibGVfZXZlbnRsb2cgPSBmYWxzZQonJycKCiJjZGgudG9tbCIgPSAnJycKIyBUaGUgdHRycGMgc29jayBvZiBDREggdGhhdCBpcyB1c2VkIHRvIGxpc3RlbiB0byB0aGUgcmVxdWVzdHMKc29ja2V0ID0gInVuaXg6Ly8vcnVuL2NvbmZpZGVudGlhbC1jb250YWluZXJzL2NkaC5zb2NrIgoKIyBLQkMgcmVsYXRlZCBjb25maWdzLgpba2JjXQojIFJlcXVpcmVkLiBUaGUgS0JDIG5hbWUuIEl0IGNvdWxkIGJlIGBjY19rYmNgLCBgb25saW5lX3Nldl9rYmNgIG9yCiMgYG9mZmxpbmVfZnNfa2JjYC4gQWxsIHRoZSBpdGVtcyB1bmRlciBgW2NyZWRlbnRpYWxzXWAgd2lsbCBiZQojIHJldHJpZXZlZCB1c2luZyB0aGUga2JjLgpuYW1lID0gImNjX2tiYyIKCiMgUmVxdWlyZWQuIFRoZSBVUkwgb2YgS0JTLiBJZiBgbmFtZWAgaXMgZWl0aGVyIGBjY19rYmNgIG9yCiMgYG9ubGluZV9zZXZfa2JjYCwgdGhpcyBVUkwgd2lsbCBiZSB1c2VkIHRvIGNvbm5lY3QgdG8gdGhlCiMgQ29Db0tCUyAoZm9yIGNjX2tiYykgb3IgU2ltcGxlLUtCUyAoZm9yIG9ubGluZV9zZXZfa2JjKS4gSWYKIyBgbmFtZWAgaXMgYG9mZmxpbmVfZnNfa2JjYCwgVGhpcyBVUkwgd2lsbCBiZSBpZ25vcmVkLgp1cmwgPSAiaHR0cHM6Ly84LjIxOC4yLjIyMzo4MDgwIgoKIyBPcHRpb25hbC4gVGhlIHB1YmxpYyBrZXkgY2VydCBvZiBLQlMuIElmIG5vdCBnaXZlbiwgQ0RIIHdpbGwKIyB0cnkgdG8gdXNlIEhUVFAgdG8gY29ubmVjdCB0aGUgc2VydmVyLgojIGtic19jZXJ0ID0gIiIKCiMgY3JlZGVudGlhbHMgYXJlIGl0ZW1zIHRoYXQgd2lsbCBiZSByZXRyaWV2ZWQgZnJvbSBLQlMgd2hlbiBDREgKIyBpcyBsYXVuY2hlZC4gYHJlc291cmNlX3VyaWAgcmVmZXJzIHRvIHRoZSBLQlMgcmVzb3VyY2UgdXJpIGFuZAojIGBwYXRoYCBpcyB3aGVyZSB0byBwbGFjZSB0aGUgZmlsZS4KIyBgcGF0aGAgbXVzdCBiZSB3aXRoIHByZWZpeCBgL3J1bi9jb25maWRlbnRpYWwtY29udGFpbmVycy9jZGhgLAojIG9yIGl0IHdpbGwgYmUgYmxvY2tlZCBieSBDREguCiMgW1tjcmVkZW50aWFsc11dCiMgcGF0aCA9ICIvcnVuL2NvbmZpZGVudGlhbC1jb250YWluZXJzL2NkaC9rbXMtY3JlZGVudGlhbC9hbGl5dW4vZWNzUmFtUm9sZS5qc29uIgojIHJlc291cmNlX3VyaSA9ICJrYnM6Ly8vZGVmYXVsdC9hbGl5dW4vZWNzX3JhbV9yb2xlIgoKIyBbW2NyZWRlbnRpYWxzXV0KIyBwYXRoID0gIi9ydW4vY29uZmlkZW50aWFsLWNvbnRhaW5lcnMvY2RoL3Rlc3QvZmlsZSIKIyByZXNvdXJjZV91cmkgPSAia2JzOi8vL2RlZmF1bHQvdGVzdC9maWxlIgoKW2ltYWdlXQoKIyBUaGUgbWF4aW11bSBudW1iZXIgb2YgbGF5ZXJzIGRvd25sb2FkZWQgY29uY3VycmVudGx5IHdoZW4KIyBwdWxsaW5nIG9uZSBzcGVjaWZpYyBpbWFnZS4KIwojIFRoaXMgZGVmYXVsdHMgdG8gMy4KbWF4X2NvbmN1cnJlbnRfbGF5ZXJfZG93bmxvYWRzX3Blcl9pbWFnZSA9IDMKCiMgU2lnc3RvcmUgY29uZmlnIGZpbGUgVVJJIGZvciBzaW1wbGUgc2lnbmluZyBzY2hlbWUuCiMKIyBXaGVuIGBpbWFnZV9zZWN1cml0eV9wb2xpY3lfdXJpYCBpcyBzZXQgYW5kIGBTaW1wbGVTaWduaW5nYCAoc2lnbmVkQnkpIGlzCiMgdXNlZCBpbiB0aGUgcG9saWN5LCB0aGUgc2lnbmF0dXJlcyBvZiB0aGUgaW1hZ2VzIHdvdWxkIGJlIHVzZWQgZm9yIGltYWdlCiMgc2lnbmF0dXJlIHZhbGlkYXRpb24uIFRoaXMgcG9saWN5IHdpbGwgcmVjb3JkIHdoZXJlIHRoZSBzaWduYXR1cmVzIGlzLgojCiMgTm93IGl0IHN1cHBvcnRzIHR3byBkaWZmZXJlbnQgZm9ybXM6CiMgLSBgS0JTIFVSSWA6IHRoZSBzaWdzdG9yZSBjb25maWcgZmlsZSB3aWxsIGJlIGZldGNoZWQgZnJvbSBLQlMsCiMgZS5nLiBga2JzOi8vL2RlZmF1bHQvc2lnc3RvcmUtY29uZmlnL3Rlc3RgLgojIC0gYExvY2FsIFBhdGhgOiB0aGUgc2lnc3RvcmUgY29uZmlnIGZpbGUgd2lsbCBiZSBmZXRjaGVkIGZyb20gc29tZXdoZXJlIGxvY2FsbHksCiMgZS5nLiBgZmlsZTovLy9ldGMvc2ltcGxlLXNpZ25pbmcueWFtbGAuCiMKIyBCeSBkZWZhdWx0IHRoaXMgdmFsdWUgaXMgbm90IHNldC4Kc2lnc3RvcmVfY29uZmlnX3VyaSA9ICJrYnM6Ly8vZGVmYXVsdC9zaWdzdG9yZS1jb25maWcvdGVzdCIKCiMgSWYgYW55IGltYWdlIHNlY3VyaXR5IHBvbGljeSB3b3VsZCBiZSB1c2VkIHRvIGNvbnRyb2wgdGhlIGltYWdlIHB1bGxpbmcKIyBsaWtlIHNpZ25hdHVyZSB2ZXJpZmljYXRpb24sIHRoaXMgZmllbGQgaXMgdXNlZCB0byBzZXQgdGhlIFVSSSBvZiB0aGUKIyBwb2xpY3kgZmlsZS4KIwojIE5vdyBpdCBzdXBwb3J0cyB0d28gZGlmZmVyZW50IGZvcm1zOgojIC0gYEtCUyBVUklgOiB0aGUgaWFtZ2Ugc2VjdXJpdHkgcG9saWN5IHdpbGwgYmUgZmV0Y2hlZCBmcm9tIEtCUy4KIyAtIGBMb2NhbCBQYXRoYDogdGhlIHNlY3VyaXR5IHBvbGljeSB3aWxsIGJlIGZldGNoZWQgZnJvbSBzb21ld2hlcmUgbG9jYWxseS4KIyBlLmcuIGBmaWxlOi8vL2V0Yy9pbWFnZS1wb2xpY3kuanNvbmAuCiMKIyBUaGUgcG9saWN5IGZvbGxvd3MgdGhlIGZvcm1hdCBvZgojIDxodHRwczovL2dpdGh1Yi5jb20vY29udGFpbmVycy9pbWFnZS9ibG9iL21haW4vZG9jcy9jb250YWluZXJzLXBvbGljeS5qc29uLjUubWQ+LgojCiMgQXQgdGhlIHNhbWUgdGltZSwgc29tZSBlbmhlbmNlbWVudHMgYmFzZWQgb24gQ29DbyBpcyB1c2VkLCB0aGF0IGlzIHRoZQojIGBrZXlQYXRoYCBmaWVsZCBjYW4gYmUgZmlsbGVkIHdpdGggYSBLQlMgVVJJIGxpa2UgYGticzovLy9kZWZhdWx0L2tleS8xYAojCiMgQnkgZGVmYXVsdCJpdHktcG9saWN5L3Rlc3QiCgojIElmIGFueSBjcmVkZW50aWFsIGF1dGggKEJhc2UpIHdvdWxkIGJlIHVzZWQgdG8gY29ubmVjdCB0byBkb3dubG9hZAojIGltYWdlIGZyb20gcHJpdmF0ZSByZWdpc3RyeSwgdGhpcyBmaWVsZCBpcyB1c2VkIHRvIHNldCB0aGUgVVJJIG9mIHRoZQojIGNyZWRlbnRpYWwgZmlsZS4KIwojIE5vdyBpdCBzdXBwb3J0cyB0d28gZGlmZmVyZW50IGZvcm1zOgojIC0gYEtCUyBVUklgOiB0aGUgcmVnaXN0cnkgYXV0aCB3aWxsIGJlIGZldGNoZWQgZnJvbSBLQlMsCiMgZS5nLiBga2JzOi8vL2RlZmF1bHQvY3JlZGVudGlhbC90ZXN0YC4KIyAtIGBMb2NhbCBQYXRoYDogdGhlIHJlZ2lzdHJ5IGF1dGggd2lsbCBiZSBmZXRjaGVkIGZyb20gc29tZXdoZXJlIGxvY2FsbHksCiMgZS5nLiBgZmlsZTovLy9ldGMvaW1hZ2UtcmVnaXN0cnktYXV0aC5qc29uYC4KIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0LgphdXRoZW50aWNhdGVkX3JlZ2lzdHJ5X2NyZWRlbnRpYWxzX3VyaSA9ICJrYnM6Ly8vZGVmYXVsdC9jcmVkZW50aWFsL3Rlc3QiCgojIFByb3h5IHRoYXQgd2lsbCBiZSB1c2VkIHRvIHB1bGwgaW1hZ2UKIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0LgojIGltYWdlX3B1bGxfcHJveHkgPSAiaHR0cDovLzEyNy4wLjAuMTo1NDMyIgoKIyBObyBwcm94eSBlbnYgdGhhdCB3aWxsIGJlIHVzZWQgdG8gcHVsbCBpbWFnZS4KIwojIFRoaXMgd2lsbCBlbnN1cmUgdGhhdCB3aGVuIHdlIGFjY2VzcyB0aGUgaW1hZ2UgcmVnaXN0cnkgd2l0aCBzcGVjaWZpZWQKIyBJUHMsIHRoZSBgaW1hZ2VfcHVsbF9wcm94eWAgd2lsbCBub3QgYmUgdXNlZC4KIwojIElmIGBpbWFnZV9wdWxsX3Byb3h5YCBpcyBub3Qgc2V0LCB0aGlzIGZpZWxkIHdpbGwgZG8gbm90aGluZy4KIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0Lgpza2lwX3Byb3h5X2lwcyA9ICIxOTIuMTY4LjAuMSxsb2NhbGhvc3QiCgojIFRvIHN1cHBvcnQgcmVnaXN0cmllcyB3aXRoIHNlbGYgc2lnbmVkIGNlcnRzLiBUaGlzIGNvbmZpZyBpdGVtCiMgaXMgdXNlZCB0byBhZGQgZXh0cmEgdHJ1c3RlZCByb290IGNlcnRpZmljYXRpb25zLiBUaGUgY2VydGlmaWNhdGVzCiMgbXVzdCBiZSBlbmNvZGVkIGJ5IFBFTS4KIwojIEJ5IGRlZmF1bHQgdGhpcyB2YWx1ZSBpcyBub3Qgc2V0LgpleHRyYV9yb290X2NlcnRpZmljYXRlcyA9IFtdCgojIFRoZSBwYXRoIHRvIHN0b3JlIHRoZSBwdWxsZWQgaW1hZ2UgbGF5ZXIgZGF0YS4KIwojIFRoaXMgdmFsdWUgZGVmYXVsdHMgdG8gYC9ydW4vaW1hZ2UtcnMvYC4Kd29ya19kaXIgPSAiL3J1bi9pbWFnZS1ycyIKJycnCgoicG9saWN5LnJlZ28iID0gJycnCiMgQ29weXJpZ2h0IChjKSAyMDIzIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbgojCiMgU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjAKIwoKcGFja2FnZSBhZ2VudF9wb2xpY3kKCmRlZmF1bHQgQWRkQVJQTmVpZ2hib3JzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgQWRkU3dhcFJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IENsb3NlU3RkaW5SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBDb3B5RmlsZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IENyZWF0ZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IENyZWF0ZVNhbmRib3hSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBEZXN0cm95U2FuZGJveFJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IEV4ZWNQcm9jZXNzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgR2V0TWV0cmljc1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IEdldE9PTUV2ZW50UmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgR3Vlc3REZXRhaWxzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgTGlzdEludGVyZmFjZXNSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBMaXN0Um91dGVzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgTWVtSG90cGx1Z0J5UHJvYmVSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBPbmxpbmVDUFVNZW1SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBQYXVzZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFB1bGxJbWFnZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFJlYWRTdHJlYW1SZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZW1vdmVDb250YWluZXJSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZW1vdmVTdGFsZVZpcnRpb2ZzU2hhcmVNb3VudHNSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZXNlZWRSYW5kb21EZXZSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBSZXN1bWVDb250YWluZXJSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBTZXRHdWVzdERhdGVUaW1lUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU2V0UG9saWN5UmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU2lnbmFsUHJvY2Vzc1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFN0YXJ0Q29udGFpbmVyUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU3RhcnRUcmFjaW5nUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgU3RhdHNDb250YWluZXJSZXF1ZXN0IDo9IHRydWUKZGVmYXVsdCBTdG9wVHJhY2luZ1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFR0eVdpblJlc2l6ZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZUNvbnRhaW5lclJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZUVwaGVtZXJhbE1vdW50c1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZUludGVyZmFjZVJlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFVwZGF0ZVJvdXRlc1JlcXVlc3QgOj0gdHJ1ZQpkZWZhdWx0IFdhaXRQcm9jZXNzUmVxdWVzdCA6PSB0cnVlCmRlZmF1bHQgV3JpdGVTdHJlYW1SZXF1ZXN0IDo9IHRydWUKJycnCglvbiA9ICIwLjEuMCIKYWxnb3JpdGhtID0gInNoYTI1NiIKW2RhdGFdCgoiYWEudG9tbCIg
```

### Backup

If you comment out the longest input line and use `"123"` on the next line as the file content, the output is as expected.

Pull request:
Squashfs: fix error format when file larger than block size
https://dr-emann.github.io/squashfs/squashfs.html#_file_inodes

Due to SquashFS spec, file inode's 'blocks start' field means the offset from the beginning of the file.

This commit also fixes the fragmentData location calculation.

Finally, due to Spec, if a file does not have fragment data, its frag index should be all 0xF.

Fixes #282

Patch:
diff --git a/filesystem/squashfs/file.go b/filesystem/squashfs/file.go
index d3c08f8..d632175 100644
--- a/filesystem/squashfs/file.go
+++ b/filesystem/squashfs/file.go
@@ -47,7 +47,7 @@ func (fl *File) Read(b []byte) (int, error) {
 	// 5- read in and uncompress the necessary blocks
 	fs := fl.filesystem
 	size := fl.size() - fl.offset
-	location := int64(fl.startBlock)
+	location := int64(fl.blocksStart)
 	maxRead := len(b)
 
 	// if there is nothing left to read, just return EOF
diff --git a/filesystem/squashfs/finalize.go b/filesystem/squashfs/finalize.go
index 41e3235..b23cd99 100644
--- a/filesystem/squashfs/finalize.go
+++ b/filesystem/squashfs/finalize.go
@@ -137,11 +137,11 @@ func (fs *FileSystem) Finalize(options FinalizeOptions) error {
 	// write file fragments
 	//
 	fragmentBlockStart := location
-	fragmentBlocks, fragsWritten, err := writeFragmentBlocks(fileList, f, fs.workspace, blocksize, options, fragmentBlockStart)
+	fragmentBlocks, _, err := writeFragmentBlocks(fileList, f, fs.workspace, blocksize, options, fragmentBlockStart)
 	if err != nil {
 		return fmt.Errorf("error writing file fragment blocks: %v", err)
 	}
-	location += fragsWritten
+	location += int64(len(fragmentBlocks) * blocksize)
 
 	// extract extended attributes, and save them for later; these are written at the very end
 	// this must be done *before* creating inodes, as inodes reference these
@@ -588,6 +588,7 @@ func writeDataBlocks(fileList []*finalizeFileInfo, f backend.WritableFile, ws st
 		}
 		allBlocks += blocks
 		allWritten += written
+		location += int64(written)
 	}
 	return allWritten, nil
 }
@@ -637,9 +638,10 @@ func writeFragmentBlocks(fileList []*finalizeFileInfo, f backend.WritableFile, w
 				compressed: compressed,
 				location:   location,
 			})
+			location += int64(blocksize)
 			// increment as all writes will be to next block block
 			fragmentBlockIndex++
-			fragmentData = fragmentData[:blocksize]
+			fragmentData = make([]byte, 0)
 		}
 
 		e.fragment = &fragmentRef{
@@ -1104,11 +1106,11 @@ func createInodes(fileList []*finalizeFileInfo, idtable map[uint32]uint16, optio
 			if e.startBlock|uint32max != uint32max || e.Size()|int64(uint32max) != int64(uint32max) || len(e.xattrs) > 0 || e.links > 0 {
 				// use extendedFile inode
 				ef := &extendedFile{
-					startBlock: e.startBlock,
-					fileSize:   uint64(e.Size()),
-					blockSizes: e.blocks,
-					links:      e.links,
-					xAttrIndex: e.xAttrIndex,
+					blocksStart: uint64(e.dataLocation),
+					fileSize:    uint64(e.Size()),
+					blockSizes:  e.blocks,
+					links:       e.links,
+					xAttrIndex:  e.xAttrIndex,
 				}
 				if e.fragment != nil {
 					ef.fragmentBlockIndex = e.fragment.block
@@ -1119,13 +1121,15 @@ func createInodes(fileList []*finalizeFileInfo, idtable map[uint32]uint16, optio
 			} else {
 				// use basicFile
 				bf := &basicFile{
-					startBlock: uint32(e.startBlock),
-					fileSize:   uint32(e.Size()),
-					blockSizes: e.blocks,
+					blocksStart: uint32(e.dataLocation),
+					fileSize:    uint32(e.Size()),
+					blockSizes:  e.blocks,
 				}
 				if e.fragment != nil {
 					bf.fragmentBlockIndex = e.fragment.block
 					bf.fragmentOffset = e.fragment.offset
+				} else {
+					bf.fragmentBlockIndex = 0xffffffff
 				}
 				in = bf
 				inodeT = inodeBasicFile
diff --git a/filesystem/squashfs/inode.go b/filesystem/squashfs/inode.go
index 96b3c13..d278ba7 100644
--- a/filesystem/squashfs/inode.go
+++ b/filesystem/squashfs/inode.go
@@ -368,7 +368,7 @@ func parseDirectoryIndexes(b []byte, count int) ([]*directoryIndex, error) {
 
 // basicFile
 type basicFile struct {
-	startBlock         uint32 // block count from the start of the data section where data for this file is stored
+	blocksStart        uint32 // The offset from the start of the archive to the first data block.
 	fragmentBlockIndex uint32
 	fragmentOffset     uint32
 	fileSize           uint32
@@ -391,12 +391,12 @@ func (i basicFile) equal(o inodeBody) bool {
 			return false
 		}
 	}
-	return i.startBlock == oi.startBlock && i.fragmentOffset == oi.fragmentOffset && i.fragmentBlockIndex == oi.fragmentBlockIndex && i.fileSize == oi.fileSize
+	return i.blocksStart == oi.blocksStart && i.fragmentOffset == oi.fragmentOffset && i.fragmentBlockIndex == oi.fragmentBlockIndex && i.fileSize == oi.fileSize
 }
 
 func (i basicFile) toBytes() []byte {
 	b := make([]byte, 16+4*len(i.blockSizes))
-	binary.LittleEndian.PutUint32(b[0:4], i.startBlock)
+	binary.LittleEndian.PutUint32(b[0:4], i.blocksStart)
 	binary.LittleEndian.PutUint32(b[4:8], i.fragmentBlockIndex)
 	binary.LittleEndian.PutUint32(b[8:12], i.fragmentOffset)
 	binary.LittleEndian.PutUint32(b[12:16], i.fileSize)
@@ -413,7 +413,7 @@ func (i basicFile) xattrIndex() (uint32, bool) {
 }
 func (i basicFile) toExtended() extendedFile {
 	return extendedFile{
-		startBlock:         uint64(i.startBlock),
+		blocksStart:        uint64(i.blocksStart),
 		fileSize:           uint64(i.fileSize),
 		sparse:             0,
 		links:              0,
@@ -433,7 +433,7 @@ func parseBasicFile(b []byte, blocksize int) (*basicFile, int, error) {
 	}
 	fileSize := binary.LittleEndian.Uint32(b[12:16])
 	d := &basicFile{
-		startBlock:         binary.LittleEndian.Uint32(b[0:4]),
+		blocksStart:        binary.LittleEndian.Uint32(b[0:4]),
 		fragmentBlockIndex: binary.LittleEndian.Uint32(b[4:8]),
 		fragmentOffset:     binary.LittleEndian.Uint32(b[8:12]),
 		fileSize:           fileSize,
@@ -455,7 +455,7 @@ func parseBasicFile(b []byte, blocksize int) (*basicFile, int, error) {
 
 // extendedFile
 type extendedFile struct {
-	startBlock         uint64
+	blocksStart        uint64
 	fileSize           uint64
 	sparse             uint64
 	links              uint32
@@ -481,7 +481,7 @@ func (i extendedFile) equal(o inodeBody) bool {
 			return false
 		}
 	}
-	return i.startBlock == oi.startBlock &&
+	return i.blocksStart == oi.blocksStart &&
 		i.fragmentOffset == oi.fragmentOffset &&
 		i.fragmentBlockIndex == oi.fragmentBlockIndex &&
 		i.fileSize == oi.fileSize &&
@@ -492,7 +492,7 @@ func (i extendedFile) equal(o inodeBody) bool {
 
 func (i extendedFile) toBytes() []byte {
 	b := make([]byte, 40+4*len(i.blockSizes))
-	binary.LittleEndian.PutUint64(b[0:8], i.startBlock)
+	binary.LittleEndian.PutUint64(b[0:8], i.blocksStart)
 	binary.LittleEndian.PutUint64(b[8:16], i.fileSize)
 	binary.LittleEndian.PutUint64(b[16:24], i.sparse)
 	binary.LittleEndian.PutUint32(b[24:28], i.links)
@@ -521,7 +521,7 @@ func parseExtendedFile(b []byte, blocksize int) (*extendedFile, int, error) {
 	}
 	fileSize := binary.LittleEndian.Uint64(b[8:16])
 	d := &extendedFile{
-		startBlock:         binary.LittleEndian.Uint64(b[0:8]),
+		blocksStart:        binary.LittleEndian.Uint64(b[0:8]),
 		fileSize:           fileSize,
 		sparse:             binary.LittleEndian.Uint64(b[16:24]),
 		links:              binary.LittleEndian.Uint32(b[24:28]),


Test patch:
diff --git a/filesystem/squashfs/const_internal_test.go b/filesystem/squashfs/const_internal_test.go
index 008c28d..6f82d29 100644
--- a/filesystem/squashfs/const_internal_test.go
+++ b/filesystem/squashfs/const_internal_test.go
@@ -36,7 +36,7 @@ func testGetFirstInodeHeader() *inodeHeader {
 }
 func testGetFirstInodeBody() inodeBody {
 	return extendedFile{
-		startBlock:         0,
+		blocksStart:        0,
 		fragmentBlockIndex: 0,
 		fileSize:           7,
 		fragmentOffset:     0,
@@ -95,7 +95,7 @@ var (
 
 	// this is for /foo/filename_0
 	testBasicFile = &basicFile{
-		startBlock:         0,
+		blocksStart:        0,
 		fragmentBlockIndex: 0,
 		fileSize:           0xb,
 		fragmentOffset:     0xc,
@@ -240,7 +240,7 @@ func GetTestFileSmall(f fs.File, c Compressor) (*File, error) {
 	}
 	testFs.compressor = c
 	ef := &extendedFile{
-		startBlock:         superblockSize,
+		blocksStart:        superblockSize,
 		fileSize:           7,
 		sparse:             0,
 		links:              0,
@@ -269,7 +269,7 @@ func GetTestFileBig(f fs.File, c Compressor) (*File, error) {
 	fragSize := uint64(5)
 	size := uint64(testFs.blocksize) + fragSize
 	ef := &extendedFile{
-		startBlock:         superblockSize,
+		blocksStart:        superblockSize,
 		fileSize:           size,
 		sparse:             0,
 		links:              0,
diff --git a/filesystem/squashfs/inode_internal_test.go b/filesystem/squashfs/inode_internal_test.go
index 4891003..e8e8c45 100644
--- a/filesystem/squashfs/inode_internal_test.go
+++ b/filesystem/squashfs/inode_internal_test.go
@@ -260,8 +260,8 @@ func TestBasicFile(t *testing.T) {
 		if ext.size() != f.size() {
 			t.Errorf("Mismatched sizes actual %d expected %d", ext.size(), f.size())
 		}
-		if ext.startBlock != uint64(f.startBlock) {
-			t.Errorf("Mismatched startBlock actual %d expected %d", ext.startBlock, f.startBlock)
+		if ext.blocksStart != uint64(f.blocksStart) {
+			t.Errorf("Mismatched startBlock actual %d expected %d", ext.blocksStart, f.blocksStart)
 		}
 		if ext.fragmentOffset != f.fragmentOffset {
 			t.Errorf("Mismatched fragmentOffset actual %d expected %d", ext.fragmentOffset, f.fragmentOffset)