1// Copyright 2018 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package elf
16
17import (
18	"io"
19	"os"
20)
21
22// errorReader returns error from all operations.
23type errorReader struct {
24	error
25}
26
27func (r errorReader) Read(p []byte) (n int, err error) {
28	return 0, r.error
29}
30
31func (r errorReader) ReadAt(p []byte, off int64) (n int, err error) {
32	return 0, r.error
33}
34
35func (r errorReader) Seek(offset int64, whence int) (int64, error) {
36	return 0, r.error
37}
38
39func (r errorReader) Close() error {
40	return r.error
41}
42
43// readSeekerFromReader converts an io.Reader into an io.ReadSeeker.
44// In general Seek may not be efficient, but it is optimized for
45// common cases such as seeking to the end to find the length of the
46// data.
47type readSeekerFromReader struct {
48	reset  func() (io.Reader, error)
49	r      io.Reader
50	size   int64
51	offset int64
52}
53
54func (r *readSeekerFromReader) start() {
55	x, err := r.reset()
56	if err != nil {
57		r.r = errorReader{err}
58	} else {
59		r.r = x
60	}
61	r.offset = 0
62}
63
64func (r *readSeekerFromReader) Read(p []byte) (n int, err error) {
65	if r.r == nil {
66		r.start()
67	}
68	n, err = r.r.Read(p)
69	r.offset += int64(n)
70	return n, err
71}
72
73func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) {
74	var newOffset int64
75	switch whence {
76	case seekStart:
77		newOffset = offset
78	case seekCurrent:
79		newOffset = r.offset + offset
80	case seekEnd:
81		newOffset = r.size + offset
82	default:
83		return 0, os.ErrInvalid
84	}
85
86	switch {
87	case newOffset == r.offset:
88		return newOffset, nil
89
90	case newOffset < 0, newOffset > r.size:
91		return 0, os.ErrInvalid
92
93	case newOffset == 0:
94		r.r = nil
95
96	case newOffset == r.size:
97		r.r = errorReader{io.EOF}
98
99	default:
100		if newOffset < r.offset {
101			// Restart at the beginning.
102			r.start()
103		}
104		// Read until we reach offset.
105		var buf [512]byte
106		for r.offset < newOffset {
107			b := buf[:]
108			if newOffset-r.offset < int64(len(buf)) {
109				b = buf[:newOffset-r.offset]
110			}
111			if _, err := r.Read(b); err != nil {
112				return 0, err
113			}
114		}
115	}
116	r.offset = newOffset
117	return r.offset, nil
118}
119