FileBlobCache.cpp 5.6 KB

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