MMKV.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431
  1. /*
  2. * Tencent is pleased to support the open source community by making
  3. * MMKV available.
  4. *
  5. * Copyright (C) 2018 THL A29 Limited, a Tencent company.
  6. * All rights reserved.
  7. *
  8. * Licensed under the BSD 3-Clause License (the "License"); you may not use
  9. * this file except in compliance with the License. You may obtain a copy of
  10. * the License at
  11. *
  12. * https://opensource.org/licenses/BSD-3-Clause
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. #include "CodedInputData.h"
  21. #include "CodedOutputData.h"
  22. #include "InterProcessLock.h"
  23. #include "KeyValueHolder.h"
  24. #include "MMBuffer.h"
  25. #include "MMKVLog.h"
  26. #include "MMKVMetaInfo.hpp"
  27. #include "MMKV_IO.h"
  28. #include "MemoryFile.h"
  29. #include "MiniPBCoder.h"
  30. #include "PBUtility.h"
  31. #include "ScopedLock.hpp"
  32. #include "ThreadLock.h"
  33. #include "aes/AESCrypt.h"
  34. #include "aes/openssl/openssl_aes.h"
  35. #include "aes/openssl/openssl_md5.h"
  36. #include "crc32/Checksum.h"
  37. #include <algorithm>
  38. #include <cstdio>
  39. #include <cstring>
  40. #include <unordered_set>
  41. //#include <unistd.h>
  42. #if defined(__aarch64__) && defined(__linux)
  43. # include <asm/hwcap.h>
  44. # include <sys/auxv.h>
  45. #endif
  46. #ifdef MMKV_APPLE
  47. # if __has_feature(objc_arc)
  48. # error This file must be compiled with MRC. Use -fno-objc-arc flag.
  49. # endif
  50. #endif // MMKV_APPLE
  51. using namespace std;
  52. using namespace mmkv;
  53. unordered_map<string, MMKV *> *g_instanceDic;
  54. ThreadLock *g_instanceLock;
  55. MMKVPath_t g_rootDir;
  56. static mmkv::ErrorHandler g_errorHandler;
  57. size_t mmkv::DEFAULT_MMAP_SIZE;
  58. #ifndef MMKV_WIN32
  59. constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = "specialCharacter";
  60. constexpr auto CRC_SUFFIX = ".crc";
  61. #else
  62. constexpr auto SPECIAL_CHARACTER_DIRECTORY_NAME = L"specialCharacter";
  63. constexpr auto CRC_SUFFIX = L".crc";
  64. #endif
  65. constexpr uint32_t Fixed32Size = pbFixed32Size();
  66. MMKV_NAMESPACE_BEGIN
  67. static MMKVPath_t encodeFilePath(const string &mmapID, const MMKVPath_t &rootDir);
  68. bool endsWith(const MMKVPath_t &str, const MMKVPath_t &suffix);
  69. MMKVPath_t filename(const MMKVPath_t &path);
  70. #ifndef MMKV_ANDROID
  71. MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath)
  72. : m_mmapID(mmapID)
  73. , m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
  74. , m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
  75. , m_dic(nullptr)
  76. , m_dicCrypt(nullptr)
  77. , m_file(new MemoryFile(m_path))
  78. , m_metaFile(new MemoryFile(m_crcPath))
  79. , m_metaInfo(new MMKVMetaInfo())
  80. , m_crypter(nullptr)
  81. , m_lock(new ThreadLock())
  82. , m_fileLock(new FileLock(m_metaFile->getFd()))
  83. , m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
  84. , m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
  85. , m_isInterProcess((mode & MMKV_MULTI_PROCESS) != 0) {
  86. m_actualSize = 0;
  87. m_output = nullptr;
  88. # ifndef MMKV_DISABLE_CRYPT
  89. if (cryptKey && cryptKey->length() > 0) {
  90. m_dicCrypt = new MMKVMapCrypt();
  91. m_crypter = new AESCrypt(cryptKey->data(), cryptKey->length());
  92. } else {
  93. m_dic = new MMKVMap();
  94. }
  95. # else
  96. m_dic = new MMKVMap();
  97. # endif
  98. m_needLoadFromFile = true;
  99. m_hasFullWriteback = false;
  100. m_crcDigest = 0;
  101. m_lock->initialize();
  102. m_sharedProcessLock->m_enable = m_isInterProcess;
  103. m_exclusiveProcessLock->m_enable = m_isInterProcess;
  104. // sensitive zone
  105. {
  106. SCOPED_LOCK(m_sharedProcessLock);
  107. loadFromFile();
  108. }
  109. }
  110. #endif
  111. MMKV::~MMKV() {
  112. clearMemoryCache();
  113. delete m_dic;
  114. #ifndef MMKV_DISABLE_CRYPT
  115. delete m_dicCrypt;
  116. delete m_crypter;
  117. #endif
  118. delete m_file;
  119. delete m_metaFile;
  120. delete m_metaInfo;
  121. delete m_lock;
  122. delete m_fileLock;
  123. delete m_sharedProcessLock;
  124. delete m_exclusiveProcessLock;
  125. #ifdef MMKV_ANDROID
  126. delete m_fileModeLock;
  127. delete m_sharedProcessModeLock;
  128. delete m_exclusiveProcessModeLock;
  129. #endif
  130. MMKVInfo("destruct [%s]", m_mmapID.c_str());
  131. }
  132. MMKV *MMKV::defaultMMKV(MMKVMode mode, string *cryptKey) {
  133. #ifndef MMKV_ANDROID
  134. return mmkvWithID(DEFAULT_MMAP_ID, mode, cryptKey);
  135. #else
  136. return mmkvWithID(DEFAULT_MMAP_ID, DEFAULT_MMAP_SIZE, mode, cryptKey);
  137. #endif
  138. }
  139. void initialize() {
  140. g_instanceDic = new unordered_map<string, MMKV *>;
  141. g_instanceLock = new ThreadLock();
  142. g_instanceLock->initialize();
  143. mmkv::DEFAULT_MMAP_SIZE = mmkv::getPageSize();
  144. MMKVInfo("version %s, page size %d, arch %s", MMKV_VERSION, DEFAULT_MMAP_SIZE, MMKV_ABI);
  145. // get CPU status of ARMv8 extensions (CRC32, AES)
  146. #if defined(__aarch64__) && defined(__linux__)
  147. auto hwcaps = getauxval(AT_HWCAP);
  148. # ifndef MMKV_DISABLE_CRYPT
  149. if (hwcaps & HWCAP_AES) {
  150. openssl::AES_set_encrypt_key = openssl_aes_armv8_set_encrypt_key;
  151. openssl::AES_set_decrypt_key = openssl_aes_armv8_set_decrypt_key;
  152. openssl::AES_encrypt = openssl_aes_armv8_encrypt;
  153. openssl::AES_decrypt = openssl_aes_armv8_decrypt;
  154. MMKVInfo("armv8 AES instructions is supported");
  155. } else {
  156. MMKVInfo("armv8 AES instructions is not supported");
  157. }
  158. # endif // MMKV_DISABLE_CRYPT
  159. # ifdef MMKV_USE_ARMV8_CRC32
  160. if (hwcaps & HWCAP_CRC32) {
  161. CRC32 = mmkv::armv8_crc32;
  162. MMKVInfo("armv8 CRC32 instructions is supported");
  163. } else {
  164. MMKVInfo("armv8 CRC32 instructions is not supported");
  165. }
  166. # endif // MMKV_USE_ARMV8_CRC32
  167. #endif // __aarch64__ && defined(__linux__)
  168. #if defined(MMKV_DEBUG) && !defined(MMKV_DISABLE_CRYPT)
  169. AESCrypt::testAESCrypt();
  170. KeyValueHolderCrypt::testAESToMMBuffer();
  171. #endif
  172. }
  173. ThreadOnceToken_t once_control = ThreadOnceUninitialized;
  174. void MMKV::initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel) {
  175. g_currentLogLevel = logLevel;
  176. ThreadLock::ThreadOnce(&once_control, initialize);
  177. g_rootDir = rootDir;
  178. mkPath(g_rootDir);
  179. MMKVInfo("root dir: " MMKV_PATH_FORMAT, g_rootDir.c_str());
  180. }
  181. const MMKVPath_t &MMKV::getRootDir() {
  182. return g_rootDir;
  183. }
  184. #ifndef MMKV_ANDROID
  185. MMKV *MMKV::mmkvWithID(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath) {
  186. if (mmapID.empty()) {
  187. return nullptr;
  188. }
  189. SCOPED_LOCK(g_instanceLock);
  190. auto mmapKey = mmapedKVKey(mmapID, rootPath);
  191. auto itr = g_instanceDic->find(mmapKey);
  192. if (itr != g_instanceDic->end()) {
  193. MMKV *kv = itr->second;
  194. return kv;
  195. }
  196. if (rootPath) {
  197. MMKVPath_t specialPath = (*rootPath) + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
  198. if (!isFileExist(specialPath)) {
  199. mkPath(specialPath);
  200. }
  201. MMKVInfo("prepare to load %s (id %s) from rootPath %s", mmapID.c_str(), mmapKey.c_str(), rootPath->c_str());
  202. }
  203. auto kv = new MMKV(mmapID, mode, cryptKey, rootPath);
  204. kv->m_mmapKey = mmapKey;
  205. (*g_instanceDic)[mmapKey] = kv;
  206. return kv;
  207. }
  208. #endif
  209. void MMKV::onExit() {
  210. SCOPED_LOCK(g_instanceLock);
  211. for (auto &pair : *g_instanceDic) {
  212. MMKV *kv = pair.second;
  213. kv->sync();
  214. kv->clearMemoryCache();
  215. delete kv;
  216. pair.second = nullptr;
  217. }
  218. delete g_instanceDic;
  219. g_instanceDic = nullptr;
  220. }
  221. const string &MMKV::mmapID() const {
  222. return m_mmapID;
  223. }
  224. mmkv::ContentChangeHandler g_contentChangeHandler = nullptr;
  225. void MMKV::notifyContentChanged() {
  226. if (g_contentChangeHandler) {
  227. g_contentChangeHandler(m_mmapID);
  228. }
  229. }
  230. void MMKV::checkContentChanged() {
  231. SCOPED_LOCK(m_lock);
  232. checkLoadData();
  233. }
  234. void MMKV::registerContentChangeHandler(mmkv::ContentChangeHandler handler) {
  235. g_contentChangeHandler = handler;
  236. }
  237. void MMKV::unRegisterContentChangeHandler() {
  238. g_contentChangeHandler = nullptr;
  239. }
  240. void MMKV::clearMemoryCache() {
  241. SCOPED_LOCK(m_lock);
  242. if (m_needLoadFromFile) {
  243. return;
  244. }
  245. MMKVInfo("clearMemoryCache [%s]", m_mmapID.c_str());
  246. m_needLoadFromFile = true;
  247. m_hasFullWriteback = false;
  248. clearDictionary(m_dic);
  249. #ifndef MMKV_DISABLE_CRYPT
  250. clearDictionary(m_dicCrypt);
  251. if (m_crypter) {
  252. if (m_metaInfo->m_version >= MMKVVersionRandomIV) {
  253. m_crypter->resetIV(m_metaInfo->m_vector, sizeof(m_metaInfo->m_vector));
  254. } else {
  255. m_crypter->resetIV();
  256. }
  257. }
  258. #endif
  259. delete m_output;
  260. m_output = nullptr;
  261. m_file->clearMemoryCache();
  262. m_actualSize = 0;
  263. m_metaInfo->m_crcDigest = 0;
  264. }
  265. void MMKV::close() {
  266. MMKVInfo("close [%s]", m_mmapID.c_str());
  267. SCOPED_LOCK(g_instanceLock);
  268. m_lock->lock();
  269. #ifndef MMKV_ANDROID
  270. auto itr = g_instanceDic->find(m_mmapKey);
  271. #else
  272. auto itr = g_instanceDic->find(m_mmapID);
  273. #endif
  274. if (itr != g_instanceDic->end()) {
  275. g_instanceDic->erase(itr);
  276. }
  277. delete this;
  278. }
  279. #ifndef MMKV_DISABLE_CRYPT
  280. string MMKV::cryptKey() const {
  281. SCOPED_LOCK(m_lock);
  282. if (m_crypter) {
  283. char key[AES_KEY_LEN];
  284. m_crypter->getKey(key);
  285. return {key, strnlen(key, AES_KEY_LEN)};
  286. }
  287. return "";
  288. }
  289. void MMKV::checkReSetCryptKey(const string *cryptKey) {
  290. SCOPED_LOCK(m_lock);
  291. if (m_crypter) {
  292. if (cryptKey && cryptKey->length() > 0) {
  293. string oldKey = this->cryptKey();
  294. if (oldKey != *cryptKey) {
  295. MMKVInfo("setting new aes key");
  296. delete m_crypter;
  297. auto ptr = cryptKey->data();
  298. m_crypter = new AESCrypt(ptr, cryptKey->length());
  299. checkLoadData();
  300. } else {
  301. // nothing to do
  302. }
  303. } else {
  304. MMKVInfo("reset aes key");
  305. delete m_crypter;
  306. m_crypter = nullptr;
  307. checkLoadData();
  308. }
  309. } else {
  310. if (cryptKey && cryptKey->length() > 0) {
  311. MMKVInfo("setting new aes key");
  312. auto ptr = cryptKey->data();
  313. m_crypter = new AESCrypt(ptr, cryptKey->length());
  314. checkLoadData();
  315. } else {
  316. // nothing to do
  317. }
  318. }
  319. }
  320. #endif // MMKV_DISABLE_CRYPT
  321. bool MMKV::isFileValid() {
  322. return m_file->isFileValid();
  323. }
  324. // crc
  325. // assuming m_file is valid
  326. bool MMKV::checkFileCRCValid(size_t actualSize, uint32_t crcDigest) {
  327. auto ptr = (uint8_t *) m_file->getMemory();
  328. if (ptr) {
  329. m_crcDigest = (uint32_t) CRC32(0, (const uint8_t *) ptr + Fixed32Size, (uint32_t) actualSize);
  330. if (m_crcDigest == crcDigest) {
  331. return true;
  332. }
  333. MMKVError("check crc [%s] fail, crc32:%u, m_crcDigest:%u", m_mmapID.c_str(), crcDigest, m_crcDigest);
  334. }
  335. return false;
  336. }
  337. void MMKV::recaculateCRCDigestWithIV(const void *iv) {
  338. auto ptr = (const uint8_t *) m_file->getMemory();
  339. if (ptr) {
  340. m_crcDigest = 0;
  341. m_crcDigest = (uint32_t) CRC32(0, ptr + Fixed32Size, (uint32_t) m_actualSize);
  342. writeActualSize(m_actualSize, m_crcDigest, iv, IncreaseSequence);
  343. }
  344. }
  345. void MMKV::updateCRCDigest(const uint8_t *ptr, size_t length) {
  346. if (ptr == nullptr) {
  347. return;
  348. }
  349. m_crcDigest = (uint32_t) CRC32(m_crcDigest, ptr, (uint32_t) length);
  350. writeActualSize(m_actualSize, m_crcDigest, nullptr, KeepSequence);
  351. }
  352. // set & get
  353. bool MMKV::set(bool value, MMKVKey_t key) {
  354. if (isKeyEmpty(key)) {
  355. return false;
  356. }
  357. size_t size = pbBoolSize();
  358. MMBuffer data(size);
  359. CodedOutputData output(data.getPtr(), size);
  360. output.writeBool(value);
  361. return setDataForKey(move(data), key);
  362. }
  363. bool MMKV::set(int32_t value, MMKVKey_t key) {
  364. if (isKeyEmpty(key)) {
  365. return false;
  366. }
  367. size_t size = pbInt32Size(value);
  368. MMBuffer data(size);
  369. CodedOutputData output(data.getPtr(), size);
  370. output.writeInt32(value);
  371. return setDataForKey(move(data), key);
  372. }
  373. bool MMKV::set(uint32_t value, MMKVKey_t key) {
  374. if (isKeyEmpty(key)) {
  375. return false;
  376. }
  377. size_t size = pbUInt32Size(value);
  378. MMBuffer data(size);
  379. CodedOutputData output(data.getPtr(), size);
  380. output.writeUInt32(value);
  381. return setDataForKey(move(data), key);
  382. }
  383. bool MMKV::set(int64_t value, MMKVKey_t key) {
  384. if (isKeyEmpty(key)) {
  385. return false;
  386. }
  387. size_t size = pbInt64Size(value);
  388. MMBuffer data(size);
  389. CodedOutputData output(data.getPtr(), size);
  390. output.writeInt64(value);
  391. return setDataForKey(move(data), key);
  392. }
  393. bool MMKV::set(uint64_t value, MMKVKey_t key) {
  394. if (isKeyEmpty(key)) {
  395. return false;
  396. }
  397. size_t size = pbUInt64Size(value);
  398. MMBuffer data(size);
  399. CodedOutputData output(data.getPtr(), size);
  400. output.writeUInt64(value);
  401. return setDataForKey(move(data), key);
  402. }
  403. bool MMKV::set(float value, MMKVKey_t key) {
  404. if (isKeyEmpty(key)) {
  405. return false;
  406. }
  407. size_t size = pbFloatSize();
  408. MMBuffer data(size);
  409. CodedOutputData output(data.getPtr(), size);
  410. output.writeFloat(value);
  411. return setDataForKey(move(data), key);
  412. }
  413. bool MMKV::set(double value, MMKVKey_t key) {
  414. if (isKeyEmpty(key)) {
  415. return false;
  416. }
  417. size_t size = pbDoubleSize();
  418. MMBuffer data(size);
  419. CodedOutputData output(data.getPtr(), size);
  420. output.writeDouble(value);
  421. return setDataForKey(move(data), key);
  422. }
  423. #ifndef MMKV_APPLE
  424. bool MMKV::set(const char *value, MMKVKey_t key) {
  425. if (!value) {
  426. removeValueForKey(key);
  427. return true;
  428. }
  429. return setDataForKey(MMBuffer((void *) value, strlen(value), MMBufferNoCopy), key, true);
  430. }
  431. bool MMKV::set(const string &value, MMKVKey_t key) {
  432. if (isKeyEmpty(key)) {
  433. return false;
  434. }
  435. return setDataForKey(MMBuffer((void *) value.data(), value.length(), MMBufferNoCopy), key, true);
  436. }
  437. bool MMKV::set(const MMBuffer &value, MMKVKey_t key) {
  438. if (isKeyEmpty(key)) {
  439. return false;
  440. }
  441. // delay write the size needed for encoding value
  442. // avoid memory copying
  443. return setDataForKey(MMBuffer(value.getPtr(), value.length(), MMBufferNoCopy), key, true);
  444. }
  445. bool MMKV::set(const vector<string> &v, MMKVKey_t key) {
  446. if (isKeyEmpty(key)) {
  447. return false;
  448. }
  449. auto data = MiniPBCoder::encodeDataWithObject(v);
  450. return setDataForKey(move(data), key);
  451. }
  452. bool MMKV::getString(MMKVKey_t key, string &result) {
  453. if (isKeyEmpty(key)) {
  454. return false;
  455. }
  456. SCOPED_LOCK(m_lock);
  457. SCOPED_LOCK(m_sharedProcessLock);
  458. auto data = getDataForKey(key);
  459. if (data.length() > 0) {
  460. try {
  461. CodedInputData input(data.getPtr(), data.length());
  462. result = input.readString();
  463. return true;
  464. } catch (std::exception &exception) {
  465. MMKVError("%s", exception.what());
  466. }
  467. }
  468. return false;
  469. }
  470. bool MMKV::getBytes(MMKVKey_t key, mmkv::MMBuffer &result) {
  471. if (isKeyEmpty(key)) {
  472. return false;
  473. }
  474. SCOPED_LOCK(m_lock);
  475. SCOPED_LOCK(m_sharedProcessLock);
  476. auto data = getDataForKey(key);
  477. if (data.length() > 0) {
  478. try {
  479. CodedInputData input(data.getPtr(), data.length());
  480. result = move(input.readData());
  481. return true;
  482. } catch (std::exception &exception) {
  483. MMKVError("%s", exception.what());
  484. }
  485. }
  486. return false;
  487. }
  488. MMBuffer MMKV::getBytes(MMKVKey_t key) {
  489. if (isKeyEmpty(key)) {
  490. return MMBuffer();
  491. }
  492. SCOPED_LOCK(m_lock);
  493. SCOPED_LOCK(m_sharedProcessLock);
  494. auto data = getDataForKey(key);
  495. if (data.length() > 0) {
  496. try {
  497. CodedInputData input(data.getPtr(), data.length());
  498. return input.readData();
  499. } catch (std::exception &exception) {
  500. MMKVError("%s", exception.what());
  501. }
  502. }
  503. return MMBuffer();
  504. }
  505. bool MMKV::getVector(MMKVKey_t key, vector<string> &result) {
  506. if (isKeyEmpty(key)) {
  507. return false;
  508. }
  509. SCOPED_LOCK(m_lock);
  510. SCOPED_LOCK(m_sharedProcessLock);
  511. auto data = getDataForKey(key);
  512. if (data.length() > 0) {
  513. try {
  514. result = MiniPBCoder::decodeVector(data);
  515. return true;
  516. } catch (std::exception &exception) {
  517. MMKVError("%s", exception.what());
  518. }
  519. }
  520. return false;
  521. }
  522. #endif // MMKV_APPLE
  523. bool MMKV::getBool(MMKVKey_t key, bool defaultValue, bool *hasValue) {
  524. if (isKeyEmpty(key)) {
  525. if (hasValue != nullptr) {
  526. *hasValue = false;
  527. }
  528. return defaultValue;
  529. }
  530. SCOPED_LOCK(m_lock);
  531. SCOPED_LOCK(m_sharedProcessLock);
  532. auto data = getDataForKey(key);
  533. if (data.length() > 0) {
  534. try {
  535. CodedInputData input(data.getPtr(), data.length());
  536. if (hasValue != nullptr) {
  537. *hasValue = true;
  538. }
  539. return input.readBool();
  540. } catch (std::exception &exception) {
  541. MMKVError("%s", exception.what());
  542. }
  543. }
  544. if (hasValue != nullptr) {
  545. *hasValue = false;
  546. }
  547. return defaultValue;
  548. }
  549. int32_t MMKV::getInt32(MMKVKey_t key, int32_t defaultValue, bool *hasValue) {
  550. if (isKeyEmpty(key)) {
  551. if (hasValue != nullptr) {
  552. *hasValue = false;
  553. }
  554. return defaultValue;
  555. }
  556. SCOPED_LOCK(m_lock);
  557. SCOPED_LOCK(m_sharedProcessLock);
  558. auto data = getDataForKey(key);
  559. if (data.length() > 0) {
  560. try {
  561. CodedInputData input(data.getPtr(), data.length());
  562. if (hasValue != nullptr) {
  563. *hasValue = true;
  564. }
  565. return input.readInt32();
  566. } catch (std::exception &exception) {
  567. MMKVError("%s", exception.what());
  568. }
  569. }
  570. if (hasValue != nullptr) {
  571. *hasValue = false;
  572. }
  573. return defaultValue;
  574. }
  575. uint32_t MMKV::getUInt32(MMKVKey_t key, uint32_t defaultValue, bool *hasValue) {
  576. if (isKeyEmpty(key)) {
  577. if (hasValue != nullptr) {
  578. *hasValue = false;
  579. }
  580. return defaultValue;
  581. }
  582. SCOPED_LOCK(m_lock);
  583. SCOPED_LOCK(m_sharedProcessLock);
  584. auto data = getDataForKey(key);
  585. if (data.length() > 0) {
  586. try {
  587. CodedInputData input(data.getPtr(), data.length());
  588. if (hasValue != nullptr) {
  589. *hasValue = true;
  590. }
  591. return input.readUInt32();
  592. } catch (std::exception &exception) {
  593. MMKVError("%s", exception.what());
  594. }
  595. }
  596. if (hasValue != nullptr) {
  597. *hasValue = false;
  598. }
  599. return defaultValue;
  600. }
  601. int64_t MMKV::getInt64(MMKVKey_t key, int64_t defaultValue, bool *hasValue) {
  602. if (isKeyEmpty(key)) {
  603. if (hasValue != nullptr) {
  604. *hasValue = false;
  605. }
  606. return defaultValue;
  607. }
  608. SCOPED_LOCK(m_lock);
  609. SCOPED_LOCK(m_sharedProcessLock);
  610. auto data = getDataForKey(key);
  611. if (data.length() > 0) {
  612. try {
  613. CodedInputData input(data.getPtr(), data.length());
  614. if (hasValue != nullptr) {
  615. *hasValue = true;
  616. }
  617. return input.readInt64();
  618. } catch (std::exception &exception) {
  619. MMKVError("%s", exception.what());
  620. }
  621. }
  622. if (hasValue != nullptr) {
  623. *hasValue = false;
  624. }
  625. return defaultValue;
  626. }
  627. uint64_t MMKV::getUInt64(MMKVKey_t key, uint64_t defaultValue, bool *hasValue) {
  628. if (isKeyEmpty(key)) {
  629. if (hasValue != nullptr) {
  630. *hasValue = false;
  631. }
  632. return defaultValue;
  633. }
  634. SCOPED_LOCK(m_lock);
  635. SCOPED_LOCK(m_sharedProcessLock);
  636. auto data = getDataForKey(key);
  637. if (data.length() > 0) {
  638. try {
  639. CodedInputData input(data.getPtr(), data.length());
  640. if (hasValue != nullptr) {
  641. *hasValue = true;
  642. }
  643. return input.readUInt64();
  644. } catch (std::exception &exception) {
  645. MMKVError("%s", exception.what());
  646. }
  647. }
  648. if (hasValue != nullptr) {
  649. *hasValue = false;
  650. }
  651. return defaultValue;
  652. }
  653. float MMKV::getFloat(MMKVKey_t key, float defaultValue, bool *hasValue) {
  654. if (isKeyEmpty(key)) {
  655. if (hasValue != nullptr) {
  656. *hasValue = false;
  657. }
  658. return defaultValue;
  659. }
  660. SCOPED_LOCK(m_lock);
  661. SCOPED_LOCK(m_sharedProcessLock);
  662. auto data = getDataForKey(key);
  663. if (data.length() > 0) {
  664. try {
  665. CodedInputData input(data.getPtr(), data.length());
  666. if (hasValue != nullptr) {
  667. *hasValue = true;
  668. }
  669. return input.readFloat();
  670. } catch (std::exception &exception) {
  671. MMKVError("%s", exception.what());
  672. }
  673. }
  674. if (hasValue != nullptr) {
  675. *hasValue = false;
  676. }
  677. return defaultValue;
  678. }
  679. double MMKV::getDouble(MMKVKey_t key, double defaultValue, bool *hasValue) {
  680. if (isKeyEmpty(key)) {
  681. if (hasValue != nullptr) {
  682. *hasValue = false;
  683. }
  684. return defaultValue;
  685. }
  686. SCOPED_LOCK(m_lock);
  687. SCOPED_LOCK(m_sharedProcessLock);
  688. auto data = getDataForKey(key);
  689. if (data.length() > 0) {
  690. try {
  691. CodedInputData input(data.getPtr(), data.length());
  692. if (hasValue != nullptr) {
  693. *hasValue = true;
  694. }
  695. return input.readDouble();
  696. } catch (std::exception &exception) {
  697. MMKVError("%s", exception.what());
  698. }
  699. }
  700. if (hasValue != nullptr) {
  701. *hasValue = false;
  702. }
  703. return defaultValue;
  704. }
  705. size_t MMKV::getValueSize(MMKVKey_t key, bool actualSize) {
  706. if (isKeyEmpty(key)) {
  707. return 0;
  708. }
  709. SCOPED_LOCK(m_lock);
  710. SCOPED_LOCK(m_sharedProcessLock);
  711. auto data = getDataForKey(key);
  712. if (actualSize) {
  713. try {
  714. CodedInputData input(data.getPtr(), data.length());
  715. auto length = input.readInt32();
  716. if (length >= 0) {
  717. auto s_length = static_cast<size_t>(length);
  718. if (pbRawVarint32Size(length) + s_length == data.length()) {
  719. return s_length;
  720. }
  721. }
  722. } catch (std::exception &exception) {
  723. MMKVError("%s", exception.what());
  724. }
  725. }
  726. return data.length();
  727. }
  728. int32_t MMKV::writeValueToBuffer(MMKVKey_t key, void *ptr, int32_t size) {
  729. if (isKeyEmpty(key) || size < 0) {
  730. return -1;
  731. }
  732. auto s_size = static_cast<size_t>(size);
  733. SCOPED_LOCK(m_lock);
  734. SCOPED_LOCK(m_sharedProcessLock);
  735. auto data = getDataForKey(key);
  736. try {
  737. CodedInputData input(data.getPtr(), data.length());
  738. auto length = input.readInt32();
  739. auto offset = pbRawVarint32Size(length);
  740. if (length >= 0) {
  741. auto s_length = static_cast<size_t>(length);
  742. if (offset + s_length == data.length()) {
  743. if (s_length <= s_size) {
  744. memcpy(ptr, (uint8_t *) data.getPtr() + offset, s_length);
  745. return length;
  746. }
  747. } else {
  748. if (data.length() <= s_size) {
  749. memcpy(ptr, data.getPtr(), data.length());
  750. return static_cast<int32_t>(data.length());
  751. }
  752. }
  753. }
  754. } catch (std::exception &exception) {
  755. MMKVError("%s", exception.what());
  756. }
  757. return -1;
  758. }
  759. // enumerate
  760. bool MMKV::containsKey(MMKVKey_t key) {
  761. SCOPED_LOCK(m_lock);
  762. checkLoadData();
  763. if (m_crypter) {
  764. return m_dicCrypt->find(key) != m_dicCrypt->end();
  765. } else {
  766. return m_dic->find(key) != m_dic->end();
  767. }
  768. }
  769. size_t MMKV::count() {
  770. SCOPED_LOCK(m_lock);
  771. checkLoadData();
  772. if (m_crypter) {
  773. return m_dicCrypt->size();
  774. } else {
  775. return m_dic->size();
  776. }
  777. }
  778. size_t MMKV::totalSize() {
  779. SCOPED_LOCK(m_lock);
  780. checkLoadData();
  781. return m_file->getFileSize();
  782. }
  783. size_t MMKV::actualSize() {
  784. SCOPED_LOCK(m_lock);
  785. checkLoadData();
  786. return m_actualSize;
  787. }
  788. void MMKV::removeValueForKey(MMKVKey_t key) {
  789. if (isKeyEmpty(key)) {
  790. return;
  791. }
  792. SCOPED_LOCK(m_lock);
  793. SCOPED_LOCK(m_exclusiveProcessLock);
  794. checkLoadData();
  795. removeDataForKey(key);
  796. }
  797. #ifndef MMKV_APPLE
  798. vector<string> MMKV::allKeys() {
  799. SCOPED_LOCK(m_lock);
  800. checkLoadData();
  801. vector<string> keys;
  802. if (m_crypter) {
  803. for (const auto &itr : *m_dicCrypt) {
  804. keys.push_back(itr.first);
  805. }
  806. } else {
  807. for (const auto &itr : *m_dic) {
  808. keys.push_back(itr.first);
  809. }
  810. }
  811. return keys;
  812. }
  813. void MMKV::removeValuesForKeys(const vector<string> &arrKeys) {
  814. if (arrKeys.empty()) {
  815. return;
  816. }
  817. if (arrKeys.size() == 1) {
  818. return removeValueForKey(arrKeys[0]);
  819. }
  820. SCOPED_LOCK(m_lock);
  821. SCOPED_LOCK(m_exclusiveProcessLock);
  822. checkLoadData();
  823. size_t deleteCount = 0;
  824. if (m_crypter) {
  825. for (const auto &key : arrKeys) {
  826. auto itr = m_dicCrypt->find(key);
  827. if (itr != m_dicCrypt->end()) {
  828. m_dicCrypt->erase(itr);
  829. deleteCount++;
  830. }
  831. }
  832. } else {
  833. for (const auto &key : arrKeys) {
  834. auto itr = m_dic->find(key);
  835. if (itr != m_dic->end()) {
  836. m_dic->erase(itr);
  837. deleteCount++;
  838. }
  839. }
  840. }
  841. if (deleteCount > 0) {
  842. m_hasFullWriteback = false;
  843. fullWriteback();
  844. }
  845. }
  846. #endif // MMKV_APPLE
  847. // file
  848. void MMKV::sync(SyncFlag flag) {
  849. SCOPED_LOCK(m_lock);
  850. if (m_needLoadFromFile || !isFileValid()) {
  851. return;
  852. }
  853. SCOPED_LOCK(m_exclusiveProcessLock);
  854. m_file->msync(flag);
  855. m_metaFile->msync(flag);
  856. }
  857. void MMKV::lock() {
  858. m_exclusiveProcessLock->lock();
  859. }
  860. void MMKV::unlock() {
  861. m_exclusiveProcessLock->unlock();
  862. }
  863. bool MMKV::try_lock() {
  864. return m_exclusiveProcessLock->try_lock();
  865. }
  866. // backup
  867. static bool backupOneToDirectoryByFilePath(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
  868. File crcFile(srcPath, OpenFlag::ReadOnly);
  869. if (!crcFile.isFileValid()) {
  870. return false;
  871. }
  872. bool ret = false;
  873. {
  874. #ifdef MMKV_WIN32
  875. MMKVInfo("backup one mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
  876. #else
  877. MMKVInfo("backup one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
  878. #endif
  879. FileLock fileLock(crcFile.getFd());
  880. InterProcessLock lock(&fileLock, SharedLockType);
  881. SCOPED_LOCK(&lock);
  882. ret = copyFile(srcPath, dstPath);
  883. if (ret) {
  884. auto srcCRCPath = srcPath + CRC_SUFFIX;
  885. auto dstCRCPath = dstPath + CRC_SUFFIX;
  886. ret = copyFile(srcCRCPath, dstCRCPath);
  887. }
  888. MMKVInfo("finish backup one mmkv[%s]", mmapKey.c_str());
  889. }
  890. return ret;
  891. }
  892. bool MMKV::backupOneToDirectory(const string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath) {
  893. // we have to lock the creation of MMKV instance, regardless of in cache or not
  894. SCOPED_LOCK(g_instanceLock);
  895. MMKV *kv = nullptr;
  896. if (!compareFullPath) {
  897. auto itr = g_instanceDic->find(mmapKey);
  898. if (itr != g_instanceDic->end()) {
  899. kv = itr->second;
  900. }
  901. } else {
  902. // mmapKey is actually filename, we can't simply call find()
  903. for (auto &pair : *g_instanceDic) {
  904. if (pair.second->m_path == srcPath) {
  905. kv = pair.second;
  906. break;
  907. }
  908. }
  909. }
  910. // get one in cache, do it the easy way
  911. if (kv) {
  912. #ifdef MMKV_WIN32
  913. MMKVInfo("backup one cached mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
  914. #else
  915. MMKVInfo("backup one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
  916. #endif
  917. SCOPED_LOCK(kv->m_lock);
  918. SCOPED_LOCK(kv->m_sharedProcessLock);
  919. kv->sync();
  920. auto ret = copyFile(kv->m_path, dstPath);
  921. if (ret) {
  922. auto dstCRCPath = dstPath + CRC_SUFFIX;
  923. ret = copyFile(kv->m_crcPath, dstCRCPath);
  924. }
  925. MMKVInfo("finish backup one mmkv[%s], ret: %d", mmapKey.c_str(), ret);
  926. return ret;
  927. }
  928. // no luck with cache, do it the hard way
  929. bool ret = backupOneToDirectoryByFilePath(mmapKey, srcPath, dstPath);
  930. return ret;
  931. }
  932. bool MMKV::backupOneToDirectory(const string &mmapID, const MMKVPath_t &dstDir, const MMKVPath_t *srcDir) {
  933. auto rootPath = srcDir ? srcDir : &g_rootDir;
  934. if (*rootPath == dstDir) {
  935. return true;
  936. }
  937. mkPath(dstDir);
  938. auto encodePath = encodeFilePath(mmapID, dstDir);
  939. auto dstPath = dstDir + MMKV_PATH_SLASH + encodePath;
  940. auto mmapKey = mmapedKVKey(mmapID, rootPath);
  941. #ifdef MMKV_ANDROID
  942. // historically Android mistakenly use mmapKey as mmapID
  943. auto srcPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath);
  944. #else
  945. auto srcPath = *rootPath + MMKV_PATH_SLASH + encodePath;
  946. #endif
  947. return backupOneToDirectory(mmapKey, dstPath, srcPath, false);
  948. }
  949. bool endsWith(const MMKVPath_t &str, const MMKVPath_t &suffix) {
  950. if (str.length() >= suffix.length()) {
  951. return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
  952. } else {
  953. return false;
  954. }
  955. }
  956. MMKVPath_t filename(const MMKVPath_t &path) {
  957. auto startPos = path.rfind(MMKV_PATH_SLASH);
  958. startPos++; // don't need to check for npos, because npos+1 == 0
  959. auto filename = path.substr(startPos);
  960. return filename;
  961. }
  962. size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t &srcDir, bool isInSpecialDir) {
  963. unordered_set<MMKVPath_t> mmapIDSet;
  964. unordered_set<MMKVPath_t> mmapIDCRCSet;
  965. walkInDir(srcDir, WalkFile, [&](const MMKVPath_t &filePath, WalkType) {
  966. if (endsWith(filePath, CRC_SUFFIX)) {
  967. mmapIDCRCSet.insert(filePath);
  968. } else {
  969. mmapIDSet.insert(filePath);
  970. }
  971. });
  972. size_t count = 0;
  973. if (!mmapIDSet.empty()) {
  974. mkPath(dstDir);
  975. auto compareFullPath = isInSpecialDir;
  976. for (auto &srcPath : mmapIDSet) {
  977. auto srcCRCPath = srcPath + CRC_SUFFIX;
  978. if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) {
  979. #ifdef MMKV_WIN32
  980. MMKVWarning("crc not exist [%ws]", srcCRCPath.c_str());
  981. #else
  982. MMKVWarning("crc not exist [%s]", srcCRCPath.c_str());
  983. #endif
  984. continue;
  985. }
  986. auto basename = filename(srcPath);
  987. const auto &strBasename = MMKVPath_t2String(basename);
  988. auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &srcDir);
  989. auto dstPath = dstDir + MMKV_PATH_SLASH + basename;
  990. if (backupOneToDirectory(mmapKey, dstPath, srcPath, compareFullPath)) {
  991. count++;
  992. }
  993. }
  994. }
  995. return count;
  996. }
  997. size_t MMKV::backupAllToDirectory(const MMKVPath_t &dstDir, const MMKVPath_t *srcDir) {
  998. auto rootPath = srcDir ? srcDir : &g_rootDir;
  999. if (*rootPath == dstDir) {
  1000. return true;
  1001. }
  1002. auto count = backupAllToDirectory(dstDir, *rootPath, false);
  1003. auto specialSrcDir = *rootPath + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
  1004. if (isFileExist(specialSrcDir)) {
  1005. auto specialDstDir = dstDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
  1006. count += backupAllToDirectory(specialDstDir, specialSrcDir, true);
  1007. }
  1008. return count;
  1009. }
  1010. // restore
  1011. static bool restoreOneFromDirectoryByFilePath(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
  1012. auto dstCRCPath = dstPath + CRC_SUFFIX;
  1013. File dstCRCFile(move(dstCRCPath), OpenFlag::ReadWrite | OpenFlag::Create);
  1014. if (!dstCRCFile.isFileValid()) {
  1015. return false;
  1016. }
  1017. bool ret = false;
  1018. {
  1019. #ifdef MMKV_WIN32
  1020. MMKVInfo("restore one mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
  1021. #else
  1022. MMKVInfo("restore one mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
  1023. #endif
  1024. FileLock fileLock(dstCRCFile.getFd());
  1025. InterProcessLock lock(&fileLock, ExclusiveLockType);
  1026. SCOPED_LOCK(&lock);
  1027. ret = copyFileContent(srcPath, dstPath);
  1028. if (ret) {
  1029. auto srcCRCPath = srcPath + CRC_SUFFIX;
  1030. ret = copyFileContent(srcCRCPath, dstCRCFile.getFd());
  1031. }
  1032. MMKVInfo("finish restore one mmkv[%s]", mmapKey.c_str());
  1033. }
  1034. return ret;
  1035. }
  1036. // We can't simply replace the existing file, because other processes might have already open it.
  1037. // They won't know a difference when the file has been replaced.
  1038. // We have to let them know by overriding the existing file with new content.
  1039. bool MMKV::restoreOneFromDirectory(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath, bool compareFullPath) {
  1040. // we have to lock the creation of MMKV instance, regardless of in cache or not
  1041. SCOPED_LOCK(g_instanceLock);
  1042. MMKV *kv = nullptr;
  1043. if (!compareFullPath) {
  1044. auto itr = g_instanceDic->find(mmapKey);
  1045. if (itr != g_instanceDic->end()) {
  1046. kv = itr->second;
  1047. }
  1048. } else {
  1049. // mmapKey is actually filename, we can't simply call find()
  1050. for (auto &pair : *g_instanceDic) {
  1051. if (pair.second->m_path == dstPath) {
  1052. kv = pair.second;
  1053. break;
  1054. }
  1055. }
  1056. }
  1057. // get one in cache, do it the easy way
  1058. if (kv) {
  1059. #ifdef MMKV_WIN32
  1060. MMKVInfo("restore one cached mmkv[%s] from [%ws] to [%ws]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
  1061. #else
  1062. MMKVInfo("restore one cached mmkv[%s] from [%s] to [%s]", mmapKey.c_str(), srcPath.c_str(), dstPath.c_str());
  1063. #endif
  1064. SCOPED_LOCK(kv->m_lock);
  1065. SCOPED_LOCK(kv->m_exclusiveProcessLock);
  1066. kv->sync();
  1067. auto ret = copyFileContent(srcPath, kv->m_file->getFd());
  1068. if (ret) {
  1069. auto srcCRCPath = srcPath + CRC_SUFFIX;
  1070. ret = copyFileContent(srcCRCPath, kv->m_metaFile->getFd());
  1071. }
  1072. // reload data after restore
  1073. kv->clearMemoryCache();
  1074. kv->loadFromFile();
  1075. if (kv->m_isInterProcess) {
  1076. kv->notifyContentChanged();
  1077. }
  1078. MMKVInfo("finish restore one mmkv[%s], ret: %d", mmapKey.c_str(), ret);
  1079. return ret;
  1080. }
  1081. // no luck with cache, do it the hard way
  1082. bool ret = restoreOneFromDirectoryByFilePath(mmapKey, srcPath, dstPath);
  1083. return ret;
  1084. }
  1085. bool MMKV::restoreOneFromDirectory(const string &mmapID, const MMKVPath_t &srcDir, const MMKVPath_t *dstDir) {
  1086. auto rootPath = dstDir ? dstDir : &g_rootDir;
  1087. if (*rootPath == srcDir) {
  1088. return true;
  1089. }
  1090. mkPath(*rootPath);
  1091. auto encodePath = encodeFilePath(mmapID, *rootPath);
  1092. auto srcPath = srcDir + MMKV_PATH_SLASH + encodePath;
  1093. auto mmapKey = mmapedKVKey(mmapID, rootPath);
  1094. #ifdef MMKV_ANDROID
  1095. // historically Android mistakenly use mmapKey as mmapID
  1096. auto dstPath = *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapKey, *rootPath);
  1097. #else
  1098. auto dstPath = *rootPath + MMKV_PATH_SLASH + encodePath;
  1099. #endif
  1100. return restoreOneFromDirectory(mmapKey, srcPath, dstPath, false);
  1101. }
  1102. size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t &dstDir, bool isInSpecialDir) {
  1103. unordered_set<MMKVPath_t> mmapIDSet;
  1104. unordered_set<MMKVPath_t> mmapIDCRCSet;
  1105. walkInDir(srcDir, WalkFile, [&](const MMKVPath_t &filePath, WalkType) {
  1106. if (endsWith(filePath, CRC_SUFFIX)) {
  1107. mmapIDCRCSet.insert(filePath);
  1108. } else {
  1109. mmapIDSet.insert(filePath);
  1110. }
  1111. });
  1112. size_t count = 0;
  1113. if (!mmapIDSet.empty()) {
  1114. mkPath(dstDir);
  1115. auto compareFullPath = isInSpecialDir;
  1116. for (auto &srcPath : mmapIDSet) {
  1117. auto srcCRCPath = srcPath + CRC_SUFFIX;
  1118. if (mmapIDCRCSet.find(srcCRCPath) == mmapIDCRCSet.end()) {
  1119. #ifdef MMKV_WIN32
  1120. MMKVWarning("crc not exist [%ws]", srcCRCPath.c_str());
  1121. #else
  1122. MMKVWarning("crc not exist [%s]", srcCRCPath.c_str());
  1123. #endif
  1124. continue;
  1125. }
  1126. auto basename = filename(srcPath);
  1127. const auto &strBasename = MMKVPath_t2String(basename);
  1128. auto mmapKey = isInSpecialDir ? strBasename : mmapedKVKey(strBasename, &dstDir);
  1129. auto dstPath = dstDir + MMKV_PATH_SLASH + basename;
  1130. if (restoreOneFromDirectory(mmapKey, srcPath, dstPath, compareFullPath)) {
  1131. count++;
  1132. }
  1133. }
  1134. }
  1135. return count;
  1136. }
  1137. size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t *dstDir) {
  1138. auto rootPath = dstDir ? dstDir : &g_rootDir;
  1139. if (*rootPath == srcDir) {
  1140. return true;
  1141. }
  1142. auto count = restoreAllFromDirectory(srcDir, *rootPath, true);
  1143. auto specialSrcDir = srcDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
  1144. if (isFileExist(specialSrcDir)) {
  1145. auto specialDstDir = *rootPath + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
  1146. count += restoreAllFromDirectory(specialSrcDir, specialDstDir, false);
  1147. }
  1148. return count;
  1149. }
  1150. // callbacks
  1151. void MMKV::registerErrorHandler(ErrorHandler handler) {
  1152. SCOPED_LOCK(g_instanceLock);
  1153. g_errorHandler = handler;
  1154. }
  1155. void MMKV::unRegisterErrorHandler() {
  1156. SCOPED_LOCK(g_instanceLock);
  1157. g_errorHandler = nullptr;
  1158. }
  1159. void MMKV::registerLogHandler(LogHandler handler) {
  1160. SCOPED_LOCK(g_instanceLock);
  1161. g_logHandler = handler;
  1162. }
  1163. void MMKV::unRegisterLogHandler() {
  1164. SCOPED_LOCK(g_instanceLock);
  1165. g_logHandler = nullptr;
  1166. }
  1167. void MMKV::setLogLevel(MMKVLogLevel level) {
  1168. SCOPED_LOCK(g_instanceLock);
  1169. g_currentLogLevel = level;
  1170. }
  1171. static void mkSpecialCharacterFileDirectory() {
  1172. MMKVPath_t path = g_rootDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
  1173. mkPath(path);
  1174. }
  1175. template <typename T>
  1176. static string md5(const basic_string<T> &value) {
  1177. uint8_t md[MD5_DIGEST_LENGTH] = {};
  1178. char tmp[3] = {}, buf[33] = {};
  1179. openssl::MD5((const uint8_t *) value.c_str(), value.size() * (sizeof(T) / sizeof(uint8_t)), md);
  1180. for (auto ch : md) {
  1181. snprintf(tmp, sizeof(tmp), "%2.2x", ch);
  1182. strcat(buf, tmp);
  1183. }
  1184. return {buf};
  1185. }
  1186. static MMKVPath_t encodeFilePath(const string &mmapID) {
  1187. const char *specialCharacters = "\\/:*?\"<>|";
  1188. string encodedID;
  1189. bool hasSpecialCharacter = false;
  1190. for (auto ch : mmapID) {
  1191. if (strchr(specialCharacters, ch) != nullptr) {
  1192. encodedID = md5(mmapID);
  1193. hasSpecialCharacter = true;
  1194. break;
  1195. }
  1196. }
  1197. if (hasSpecialCharacter) {
  1198. static ThreadOnceToken_t once_control = ThreadOnceUninitialized;
  1199. ThreadLock::ThreadOnce(&once_control, mkSpecialCharacterFileDirectory);
  1200. return MMKVPath_t(SPECIAL_CHARACTER_DIRECTORY_NAME) + MMKV_PATH_SLASH + string2MMKVPath_t(encodedID);
  1201. } else {
  1202. return string2MMKVPath_t(mmapID);
  1203. }
  1204. }
  1205. static MMKVPath_t encodeFilePath(const string &mmapID, const MMKVPath_t &rootDir) {
  1206. const char *specialCharacters = "\\/:*?\"<>|";
  1207. string encodedID;
  1208. bool hasSpecialCharacter = false;
  1209. for (auto ch : mmapID) {
  1210. if (strchr(specialCharacters, ch) != nullptr) {
  1211. encodedID = md5(mmapID);
  1212. hasSpecialCharacter = true;
  1213. break;
  1214. }
  1215. }
  1216. if (hasSpecialCharacter) {
  1217. MMKVPath_t path = rootDir + MMKV_PATH_SLASH + SPECIAL_CHARACTER_DIRECTORY_NAME;
  1218. mkPath(path);
  1219. return MMKVPath_t(SPECIAL_CHARACTER_DIRECTORY_NAME) + MMKV_PATH_SLASH + string2MMKVPath_t(encodedID);
  1220. } else {
  1221. return string2MMKVPath_t(mmapID);
  1222. }
  1223. }
  1224. string mmapedKVKey(const string &mmapID, const MMKVPath_t *rootPath) {
  1225. if (rootPath && g_rootDir != (*rootPath)) {
  1226. return md5(*rootPath + MMKV_PATH_SLASH + string2MMKVPath_t(mmapID));
  1227. }
  1228. return mmapID;
  1229. }
  1230. MMKVPath_t mappedKVPathWithID(const string &mmapID, MMKVMode mode, const MMKVPath_t *rootPath) {
  1231. #ifndef MMKV_ANDROID
  1232. if (rootPath) {
  1233. #else
  1234. if (mode & MMKV_ASHMEM) {
  1235. return ashmemMMKVPathWithID(encodeFilePath(mmapID));
  1236. } else if (rootPath) {
  1237. #endif
  1238. return *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapID);
  1239. }
  1240. return g_rootDir + MMKV_PATH_SLASH + encodeFilePath(mmapID);
  1241. }
  1242. MMKVPath_t crcPathWithID(const string &mmapID, MMKVMode mode, const MMKVPath_t *rootPath) {
  1243. #ifndef MMKV_ANDROID
  1244. if (rootPath) {
  1245. #else
  1246. if (mode & MMKV_ASHMEM) {
  1247. return ashmemMMKVPathWithID(encodeFilePath(mmapID)) + CRC_SUFFIX;
  1248. } else if (rootPath) {
  1249. #endif
  1250. return *rootPath + MMKV_PATH_SLASH + encodeFilePath(mmapID) + CRC_SUFFIX;
  1251. }
  1252. return g_rootDir + MMKV_PATH_SLASH + encodeFilePath(mmapID) + CRC_SUFFIX;
  1253. }
  1254. MMKVRecoverStrategic onMMKVCRCCheckFail(const string &mmapID) {
  1255. if (g_errorHandler) {
  1256. return g_errorHandler(mmapID, MMKVErrorType::MMKVCRCCheckFail);
  1257. }
  1258. return OnErrorDiscard;
  1259. }
  1260. MMKVRecoverStrategic onMMKVFileLengthError(const string &mmapID) {
  1261. if (g_errorHandler) {
  1262. return g_errorHandler(mmapID, MMKVErrorType::MMKVFileLength);
  1263. }
  1264. return OnErrorDiscard;
  1265. }
  1266. MMKV_NAMESPACE_END