github.com/hpcng/singularity@v3.1.1+incompatible/pkg/image/squashfs.go (about) 1 // Copyright (c) 2018-2019, Sylabs Inc. All rights reserved. 2 // This software is licensed under a 3-clause BSD license. Please consult the 3 // LICENSE.md file distributed with the sources of this project regarding your 4 // rights to use or distribute this software. 5 6 package image 7 8 import ( 9 "bytes" 10 "encoding/binary" 11 "fmt" 12 "os" 13 "unsafe" 14 15 "github.com/sylabs/singularity/internal/pkg/sylog" 16 ) 17 18 const ( 19 squashfsMagic = "\x68\x73\x71\x73" 20 squashfsZlib = 1 21 squashfsLzmaComp = 2 22 squashfsLzoComp = 3 23 squashfsXzComp = 4 24 squashfsLz4Comp = 5 25 ) 26 27 type squashfsInfo struct { 28 Magic [4]byte 29 Inodes uint32 30 MkfsTime uint32 31 BlockSize uint32 32 Fragments uint32 33 Compression uint16 34 } 35 36 type squashfsFormat struct{} 37 38 // CheckSquashfsHeader checks if byte content contains a valid squashfs header 39 // and returns offset where squashfs partition start 40 func CheckSquashfsHeader(b []byte) (uint64, error) { 41 var offset uint64 42 43 o := bytes.Index(b, []byte(launchString)) 44 if o > 0 { 45 offset += uint64(o + len(launchString) + 1) 46 } 47 sinfo := &squashfsInfo{} 48 49 if uintptr(offset)+unsafe.Sizeof(sinfo) >= uintptr(len(b)) { 50 return offset, fmt.Errorf("can't find squashfs information header") 51 } 52 53 buffer := bytes.NewReader(b[offset:]) 54 55 if err := binary.Read(buffer, binary.LittleEndian, sinfo); err != nil { 56 return offset, fmt.Errorf("can't read the top of the image") 57 } 58 if bytes.Compare(sinfo.Magic[:], []byte(squashfsMagic)) != 0 { 59 return offset, fmt.Errorf("not a valid squashfs image") 60 } 61 62 if sinfo.Compression != squashfsZlib { 63 compressionType := "" 64 switch sinfo.Compression { 65 case squashfsLzmaComp: 66 compressionType = "lzma" 67 case squashfsLz4Comp: 68 compressionType = "lz4" 69 case squashfsLzoComp: 70 compressionType = "lzo" 71 case squashfsXzComp: 72 compressionType = "xz" 73 } 74 sylog.Infof("squashfs image was compressed with %s, if it failed to run, please contact image's author", compressionType) 75 } 76 return offset, nil 77 } 78 79 func (f *squashfsFormat) initializer(img *Image, fileinfo os.FileInfo) error { 80 if fileinfo.IsDir() { 81 return fmt.Errorf("not a squashfs image") 82 } 83 b := make([]byte, bufferSize) 84 if n, err := img.File.Read(b); err != nil || n != bufferSize { 85 return fmt.Errorf("can't read first %d bytes: %s", bufferSize, err) 86 } 87 offset, err := CheckSquashfsHeader(b) 88 if err != nil { 89 return err 90 } 91 img.Type = SQUASHFS 92 img.Partitions[0].Offset = offset 93 img.Partitions[0].Size = uint64(fileinfo.Size()) - offset 94 img.Partitions[0].Type = SQUASHFS 95 img.Partitions[0].Name = RootFs 96 97 if img.Writable { 98 sylog.Warningf("squashfs is not a writable filesystem") 99 img.Writable = false 100 } 101 102 return nil 103 } 104 105 func (f *squashfsFormat) openMode(writable bool) int { 106 return os.O_RDONLY 107 }