1 package squashfs 2 3 import ( 4 "errors" 5 "io" 6 7 "vimagination.zapto.org/byteio" 8 ) 9 10 const ( 11 blockSize = 1 << 13 12 blockHeaderSize = 2 13 14 metadataPointerShift = 16 15 metadataPointerMask = 0xffff 16 17 metadataBlockSizeMask = 0x7fff 18 metadataBlockCompressedMask = 0x8000 19 ) 20 21 func (s *squashfs) readMetadata(pointer, table uint64) (*blockReader, error) { 22 onDisk := int64(table + (pointer >> metadataPointerShift)) 23 24 pos := int64(pointer & metadataPointerMask) 25 if pos > blockSize { 26 return nil, ErrInvalidPointer 27 } 28 29 b := &blockReader{ 30 squashfs: s, 31 next: onDisk, 32 } 33 34 if err := b.init(pos); err != nil { 35 return nil, err 36 } 37 38 return b, nil 39 } 40 41 type blockReader struct { 42 *squashfs 43 r io.ReadSeeker 44 next int64 45 } 46 47 func (b *blockReader) nextReader() error { 48 ler := byteio.LittleEndianReader{Reader: io.NewSectionReader(b.reader, b.next, blockHeaderSize)} 49 50 header, _, err := ler.ReadUint16() 51 if err != nil { 52 return err 53 } 54 55 size := int64(header & metadataBlockSizeMask) 56 57 if size > blockSize { 58 return ErrInvalidBlockHeader 59 } 60 61 b.r = io.NewSectionReader(b.reader, b.next+blockHeaderSize, size) 62 63 if header&metadataBlockCompressedMask == 0 { 64 b.r, err = b.blockCache.getBlock(b.next, b.r, b.superblock.Compressor) 65 if err != nil { 66 return err 67 } 68 } 69 70 b.next += size 71 72 return nil 73 } 74 75 func (b *blockReader) init(skipCount int64) error { 76 if err := b.nextReader(); err != nil { 77 return err 78 } 79 80 if skipCount > 0 { 81 _, err := b.r.Seek(skipCount, io.SeekStart) 82 83 return err 84 } 85 86 return nil 87 } 88 89 func (b *blockReader) Read(p []byte) (int, error) { 90 n, err := b.r.Read(p) 91 if err == nil { 92 return n, nil 93 } 94 95 if !errors.Is(err, io.EOF) { 96 return n, err 97 } 98 99 if err = b.nextReader(); err != nil { 100 return n, err 101 } 102 103 m, err := b.Read(p[n:]) 104 n += m 105 106 return n, err 107 } 108