1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.util.apk;
18 
19 import android.system.ErrnoException;
20 import android.system.Os;
21 
22 import java.io.FileDescriptor;
23 import java.io.IOException;
24 import java.nio.ByteBuffer;
25 import java.security.DigestException;
26 
27 /**
28  * {@link DataSource} which provides data from a file descriptor by reading the sections
29  * of the file via raw read() syscall. This is slower than memory-mapping but safer.
30  */
31 class ReadFileDataSource implements DataSource {
32     private final FileDescriptor mFd;
33     private final long mFilePosition;
34     private final long mSize;
35 
36     private static final int CHUNK_SIZE = 1024 * 1024;
37 
38     /**
39      * Constructs a new {@code ReadFileDataSource} for the specified region of the file.
40      *
41      * @param fd file descriptor to read from.
42      * @param position start position of the region in the file.
43      * @param size size (in bytes) of the region.
44      */
ReadFileDataSource(FileDescriptor fd, long position, long size)45     ReadFileDataSource(FileDescriptor fd, long position, long size) {
46         mFd = fd;
47         mFilePosition = position;
48         mSize = size;
49     }
50 
51     @Override
size()52     public long size() {
53         return mSize;
54     }
55 
56     @Override
feedIntoDataDigester(DataDigester md, long offset, int size)57     public void feedIntoDataDigester(DataDigester md, long offset, int size)
58             throws IOException, DigestException {
59         try {
60             final byte[] buffer = new byte[Math.min(size, CHUNK_SIZE)];
61             final long start = mFilePosition + offset;
62             final long end = start + size;
63             for (long pos = start, curSize = Math.min(size, CHUNK_SIZE);
64                     pos < end; curSize = Math.min(end - pos, CHUNK_SIZE)) {
65                 final int readSize = Os.pread(mFd, buffer, 0, (int) curSize, pos);
66                 md.consume(ByteBuffer.wrap(buffer, 0, readSize));
67                 pos += readSize;
68             }
69         } catch (ErrnoException e) {
70             throw new IOException(e);
71         }
72     }
73 }
74