blob: 328477806f1dd040d5b454698618993664bb72d5 [file] [log] [blame]
Stan Iliev9e7cd072017-10-09 15:56:10 -04001/*
2 ** Copyright 2017, 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#include "FileBlobCache.h"
18
Dan Albertcbf81da2018-01-05 14:24:09 -080019#include <errno.h>
Tom Cherry3387cab2020-04-13 11:04:01 -070020#include <fcntl.h>
Stan Iliev9e7cd072017-10-09 15:56:10 -040021#include <inttypes.h>
Stan Iliev9e7cd072017-10-09 15:56:10 -040022#include <sys/mman.h>
23#include <sys/stat.h>
Tom Cherry28ac3b92020-04-13 15:19:23 -070024#include <unistd.h>
Stan Iliev9e7cd072017-10-09 15:56:10 -040025
Tom Cherry3387cab2020-04-13 11:04:01 -070026#include <log/log.h>
Stan Iliev9e7cd072017-10-09 15:56:10 -040027
28// Cache file header
29static const char* cacheFileMagic = "EGL$";
30static const size_t cacheFileHeaderSize = 8;
31
32namespace android {
33
34static uint32_t crc32c(const uint8_t* buf, size_t len) {
35 const uint32_t polyBits = 0x82F63B78;
36 uint32_t r = 0;
37 for (size_t i = 0; i < len; i++) {
38 r ^= buf[i];
39 for (int j = 0; j < 8; j++) {
40 if (r & 1) {
41 r = (r >> 1) ^ polyBits;
42 } else {
43 r >>= 1;
44 }
45 }
46 }
47 return r;
48}
49
50FileBlobCache::FileBlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize,
51 const std::string& filename)
52 : BlobCache(maxKeySize, maxValueSize, maxTotalSize)
53 , mFilename(filename) {
54 if (mFilename.length() > 0) {
55 size_t headerSize = cacheFileHeaderSize;
56
57 int fd = open(mFilename.c_str(), O_RDONLY, 0);
58 if (fd == -1) {
59 if (errno != ENOENT) {
60 ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(),
61 strerror(errno), errno);
62 }
63 return;
64 }
65
66 struct stat statBuf;
67 if (fstat(fd, &statBuf) == -1) {
68 ALOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
69 close(fd);
70 return;
71 }
72
73 // Sanity check the size before trying to mmap it.
74 size_t fileSize = statBuf.st_size;
75 if (fileSize > mMaxTotalSize * 2) {
76 ALOGE("cache file is too large: %#" PRIx64,
77 static_cast<off64_t>(statBuf.st_size));
78 close(fd);
79 return;
80 }
81
Yi Kong48a6cd22018-07-18 10:07:09 -070082 uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(nullptr, fileSize,
Stan Iliev9e7cd072017-10-09 15:56:10 -040083 PROT_READ, MAP_PRIVATE, fd, 0));
84 if (buf == MAP_FAILED) {
85 ALOGE("error mmaping cache file: %s (%d)", strerror(errno),
86 errno);
87 close(fd);
88 return;
89 }
90
91 // Check the file magic and CRC
92 size_t cacheSize = fileSize - headerSize;
93 if (memcmp(buf, cacheFileMagic, 4) != 0) {
94 ALOGE("cache file has bad mojo");
95 close(fd);
96 return;
97 }
98 uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
99 if (crc32c(buf + headerSize, cacheSize) != *crc) {
100 ALOGE("cache file failed CRC check");
101 close(fd);
102 return;
103 }
104
105 int err = unflatten(buf + headerSize, cacheSize);
106 if (err < 0) {
107 ALOGE("error reading cache contents: %s (%d)", strerror(-err),
108 -err);
109 munmap(buf, fileSize);
110 close(fd);
111 return;
112 }
113
114 munmap(buf, fileSize);
115 close(fd);
116 }
117}
118
119void FileBlobCache::writeToFile() {
120 if (mFilename.length() > 0) {
121 size_t cacheSize = getFlattenedSize();
122 size_t headerSize = cacheFileHeaderSize;
123 const char* fname = mFilename.c_str();
124
125 // Try to create the file with no permissions so we can write it
126 // without anyone trying to read it.
127 int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
128 if (fd == -1) {
129 if (errno == EEXIST) {
130 // The file exists, delete it and try again.
131 if (unlink(fname) == -1) {
132 // No point in retrying if the unlink failed.
133 ALOGE("error unlinking cache file %s: %s (%d)", fname,
134 strerror(errno), errno);
135 return;
136 }
137 // Retry now that we've unlinked the file.
138 fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
139 }
140 if (fd == -1) {
141 ALOGE("error creating cache file %s: %s (%d)", fname,
142 strerror(errno), errno);
143 return;
144 }
145 }
146
147 size_t fileSize = headerSize + cacheSize;
148
149 uint8_t* buf = new uint8_t [fileSize];
150 if (!buf) {
151 ALOGE("error allocating buffer for cache contents: %s (%d)",
152 strerror(errno), errno);
153 close(fd);
154 unlink(fname);
155 return;
156 }
157
158 int err = flatten(buf + headerSize, cacheSize);
159 if (err < 0) {
160 ALOGE("error writing cache contents: %s (%d)", strerror(-err),
161 -err);
162 delete [] buf;
163 close(fd);
164 unlink(fname);
165 return;
166 }
167
168 // Write the file magic and CRC
169 memcpy(buf, cacheFileMagic, 4);
170 uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
171 *crc = crc32c(buf + headerSize, cacheSize);
172
173 if (write(fd, buf, fileSize) == -1) {
174 ALOGE("error writing cache file: %s (%d)", strerror(errno),
175 errno);
176 delete [] buf;
177 close(fd);
178 unlink(fname);
179 return;
180 }
181
182 delete [] buf;
183 fchmod(fd, S_IRUSR);
184 close(fd);
185 }
186}
187
Dan Albertcbf81da2018-01-05 14:24:09 -0800188}