github.com/apptainer/singularity@v3.1.1+incompatible/pkg/image/ext3.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 16 const ( 17 extMagicOffset = 1080 18 extMagic = "\x53\xEF" 19 compatHasJournal = 0x4 20 incompatFileType = 0x2 21 incompatRecover = 0x4 22 incompatMetabg = 0x10 23 rocompatSparseSuper = 0x1 24 rocompatLargeFile = 0x2 25 rocompatBtreeDir = 0x4 26 ) 27 28 const notValidExt3ImageMessage = "file is not a valid ext3 image" 29 30 type extFSInfo struct { 31 Magic [2]byte 32 State uint16 33 Dummy [8]uint32 34 Compat uint32 35 Incompat uint32 36 Rocompat uint32 37 } 38 39 type ext3Format struct{} 40 41 // CheckExt3Header checks if byte content contains a valid ext3 header 42 // and returns offset where ext3 partition begin 43 func CheckExt3Header(b []byte) (uint64, error) { 44 var offset uint64 = extMagicOffset 45 46 o := bytes.Index(b, []byte(launchString)) 47 if o > 0 { 48 offset += uint64(o + len(launchString) + 1) 49 } 50 einfo := &extFSInfo{} 51 52 if uintptr(offset)+unsafe.Sizeof(einfo) >= uintptr(len(b)) { 53 return offset, fmt.Errorf("can't find ext3 information header") 54 } 55 buffer := bytes.NewReader(b[offset:]) 56 57 if err := binary.Read(buffer, binary.LittleEndian, einfo); err != nil { 58 return offset, fmt.Errorf("can't read the top of the image") 59 } 60 if bytes.Compare(einfo.Magic[:], []byte(extMagic)) != 0 { 61 return offset, fmt.Errorf(notValidExt3ImageMessage) 62 } 63 if einfo.Compat&compatHasJournal == 0 { 64 return offset, fmt.Errorf(notValidExt3ImageMessage) 65 } 66 if einfo.Incompat&^(incompatFileType|incompatRecover|incompatMetabg) != 0 { 67 return offset, fmt.Errorf(notValidExt3ImageMessage) 68 } 69 if einfo.Rocompat&^(rocompatSparseSuper|rocompatLargeFile|rocompatBtreeDir) != 0 { 70 return offset, fmt.Errorf(notValidExt3ImageMessage) 71 } 72 offset -= extMagicOffset 73 return offset, nil 74 } 75 76 func (f *ext3Format) initializer(img *Image, fileinfo os.FileInfo) error { 77 if fileinfo.IsDir() { 78 return fmt.Errorf("not an ext3 image") 79 } 80 b := make([]byte, bufferSize) 81 if n, err := img.File.Read(b); err != nil || n != bufferSize { 82 return fmt.Errorf("can't read first %d bytes: %s", bufferSize, err) 83 } 84 offset, err := CheckExt3Header(b) 85 if err != nil { 86 return err 87 } 88 img.Type = EXT3 89 img.Partitions[0].Offset = offset 90 img.Partitions[0].Size = uint64(fileinfo.Size()) - offset 91 img.Partitions[0].Type = EXT3 92 img.Partitions[0].Name = RootFs 93 return nil 94 } 95 96 func (f *ext3Format) openMode(writable bool) int { 97 if writable { 98 return os.O_RDWR 99 } 100 return os.O_RDONLY 101 }