react-native-mmkv-dz 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/LICENSE +219 -0
  2. package/MMKV/CHANGELOG.md +553 -0
  3. package/MMKV/Core/CMakeLists.txt +153 -0
  4. package/MMKV/Core/CodedInputData.cpp +228 -0
  5. package/MMKV/Core/CodedInputData.h +83 -0
  6. package/MMKV/Core/CodedInputDataCrypt.cpp +280 -0
  7. package/MMKV/Core/CodedInputDataCrypt.h +87 -0
  8. package/MMKV/Core/CodedInputDataCrypt_OSX.cpp +62 -0
  9. package/MMKV/Core/CodedInputData_OSX.cpp +92 -0
  10. package/MMKV/Core/CodedOutputData.cpp +174 -0
  11. package/MMKV/Core/CodedOutputData.h +82 -0
  12. package/MMKV/Core/Core.xcodeproj/project.pbxproj +702 -0
  13. package/MMKV/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  14. package/MMKV/Core/Core.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  15. package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/Core.xcscheme +67 -0
  16. package/MMKV/Core/Core.xcodeproj/xcshareddata/xcschemes/MMKVWatchCore.xcscheme +67 -0
  17. package/MMKV/Core/InterProcessLock.cpp +186 -0
  18. package/MMKV/Core/InterProcessLock.h +119 -0
  19. package/MMKV/Core/InterProcessLock_Android.cpp +103 -0
  20. package/MMKV/Core/InterProcessLock_Win32.cpp +108 -0
  21. package/MMKV/Core/KeyValueHolder.cpp +236 -0
  22. package/MMKV/Core/KeyValueHolder.h +118 -0
  23. package/MMKV/Core/MMBuffer.cpp +185 -0
  24. package/MMKV/Core/MMBuffer.h +107 -0
  25. package/MMKV/Core/MMKV.cpp +1418 -0
  26. package/MMKV/Core/MMKV.h +386 -0
  27. package/MMKV/Core/MMKVLog.cpp +127 -0
  28. package/MMKV/Core/MMKVLog.h +86 -0
  29. package/MMKV/Core/MMKVLog_Android.cpp +79 -0
  30. package/MMKV/Core/MMKVMetaInfo.hpp +81 -0
  31. package/MMKV/Core/MMKVPredef.h +245 -0
  32. package/MMKV/Core/MMKV_Android.cpp +259 -0
  33. package/MMKV/Core/MMKV_IO.cpp +1119 -0
  34. package/MMKV/Core/MMKV_IO.h +57 -0
  35. package/MMKV/Core/MMKV_OSX.cpp +347 -0
  36. package/MMKV/Core/MMKV_OSX.h +51 -0
  37. package/MMKV/Core/MemoryFile.cpp +537 -0
  38. package/MMKV/Core/MemoryFile.h +182 -0
  39. package/MMKV/Core/MemoryFile_Android.cpp +211 -0
  40. package/MMKV/Core/MemoryFile_Linux.cpp +120 -0
  41. package/MMKV/Core/MemoryFile_OSX.cpp +142 -0
  42. package/MMKV/Core/MemoryFile_Win32.cpp +536 -0
  43. package/MMKV/Core/MiniPBCoder.cpp +366 -0
  44. package/MMKV/Core/MiniPBCoder.h +129 -0
  45. package/MMKV/Core/MiniPBCoder_OSX.cpp +228 -0
  46. package/MMKV/Core/PBEncodeItem.hpp +86 -0
  47. package/MMKV/Core/PBUtility.cpp +61 -0
  48. package/MMKV/Core/PBUtility.h +153 -0
  49. package/MMKV/Core/ScopedLock.hpp +69 -0
  50. package/MMKV/Core/ThreadLock.cpp +68 -0
  51. package/MMKV/Core/ThreadLock.h +78 -0
  52. package/MMKV/Core/ThreadLock_Win32.cpp +89 -0
  53. package/MMKV/Core/aes/AESCrypt.cpp +256 -0
  54. package/MMKV/Core/aes/AESCrypt.h +107 -0
  55. package/MMKV/Core/aes/openssl/openssl_aes-armv4.S +1231 -0
  56. package/MMKV/Core/aes/openssl/openssl_aes.h +118 -0
  57. package/MMKV/Core/aes/openssl/openssl_aes_core.cpp +1044 -0
  58. package/MMKV/Core/aes/openssl/openssl_aes_locl.h +38 -0
  59. package/MMKV/Core/aes/openssl/openssl_aesv8-armx.S +308 -0
  60. package/MMKV/Core/aes/openssl/openssl_arm_arch.h +84 -0
  61. package/MMKV/Core/aes/openssl/openssl_cfb128.cpp +97 -0
  62. package/MMKV/Core/aes/openssl/openssl_md32_common.h +254 -0
  63. package/MMKV/Core/aes/openssl/openssl_md5.h +49 -0
  64. package/MMKV/Core/aes/openssl/openssl_md5_dgst.cpp +166 -0
  65. package/MMKV/Core/aes/openssl/openssl_md5_locl.h +75 -0
  66. package/MMKV/Core/aes/openssl/openssl_md5_one.cpp +30 -0
  67. package/MMKV/Core/aes/openssl/openssl_opensslconf.h +271 -0
  68. package/MMKV/Core/core.vcxproj +186 -0
  69. package/MMKV/Core/core.vcxproj.filters +150 -0
  70. package/MMKV/Core/crc32/Checksum.h +67 -0
  71. package/MMKV/Core/crc32/crc32_armv8.cpp +132 -0
  72. package/MMKV/Core/crc32/zlib/crc32.cpp +55 -0
  73. package/MMKV/Core/crc32/zlib/crc32.h +48 -0
  74. package/MMKV/Core/crc32/zlib/zconf.h +380 -0
  75. package/MMKV/Core/crc32/zlib/zutil.h +25 -0
  76. package/MMKV/LICENSE.TXT +193 -0
  77. package/MMKV/README.md +288 -0
  78. package/README.md +221 -0
  79. package/android/CMakeLists.txt +71 -0
  80. package/android/build.gradle +371 -0
  81. package/android/gradle.properties +4 -0
  82. package/android/src/main/AndroidManifest.xml +4 -0
  83. package/android/src/main/cpp/MmkvHostObject.cpp +302 -0
  84. package/android/src/main/cpp/MmkvHostObject.h +26 -0
  85. package/android/src/main/cpp/cpp-adapter.cpp +65 -0
  86. package/android/src/main/java/com/reactnativemmkv/MmkvModule.java +49 -0
  87. package/android/src/main/java/com/reactnativemmkv/MmkvPackage.java +26 -0
  88. package/cpp/TypedArray.cpp +341 -0
  89. package/cpp/TypedArray.h +175 -0
  90. package/ios/JSIUtils.h +50 -0
  91. package/ios/JSIUtils.mm +194 -0
  92. package/ios/Mmkv.xcodeproj/project.pbxproj +291 -0
  93. package/ios/MmkvHostObject.h +27 -0
  94. package/ios/MmkvHostObject.mm +299 -0
  95. package/ios/MmkvModule.h +5 -0
  96. package/ios/MmkvModule.mm +73 -0
  97. package/lib/commonjs/MMKV.js +146 -0
  98. package/lib/commonjs/MMKV.js.map +1 -0
  99. package/lib/commonjs/PlatformChecker.js +16 -0
  100. package/lib/commonjs/PlatformChecker.js.map +1 -0
  101. package/lib/commonjs/createMMKV.js +66 -0
  102. package/lib/commonjs/createMMKV.js.map +1 -0
  103. package/lib/commonjs/createMMKV.mock.js +40 -0
  104. package/lib/commonjs/createMMKV.mock.js.map +1 -0
  105. package/lib/commonjs/createMMKV.web.js +77 -0
  106. package/lib/commonjs/createMMKV.web.js.map +1 -0
  107. package/lib/commonjs/createTextEncoder.js +24 -0
  108. package/lib/commonjs/createTextEncoder.js.map +1 -0
  109. package/lib/commonjs/hooks.js +200 -0
  110. package/lib/commonjs/hooks.js.map +1 -0
  111. package/lib/commonjs/index.js +32 -0
  112. package/lib/commonjs/index.js.map +1 -0
  113. package/lib/module/MMKV.js +134 -0
  114. package/lib/module/MMKV.js.map +1 -0
  115. package/lib/module/PlatformChecker.js +9 -0
  116. package/lib/module/PlatformChecker.js.map +1 -0
  117. package/lib/module/createMMKV.js +55 -0
  118. package/lib/module/createMMKV.js.map +1 -0
  119. package/lib/module/createMMKV.mock.js +31 -0
  120. package/lib/module/createMMKV.mock.js.map +1 -0
  121. package/lib/module/createMMKV.web.js +67 -0
  122. package/lib/module/createMMKV.web.js.map +1 -0
  123. package/lib/module/createTextEncoder.js +17 -0
  124. package/lib/module/createTextEncoder.js.map +1 -0
  125. package/lib/module/hooks.js +181 -0
  126. package/lib/module/hooks.js.map +1 -0
  127. package/lib/module/index.js +3 -0
  128. package/lib/module/index.js.map +1 -0
  129. package/lib/typescript/MMKV.d.ts +137 -0
  130. package/lib/typescript/PlatformChecker.d.ts +1 -0
  131. package/lib/typescript/createMMKV.d.ts +6 -0
  132. package/lib/typescript/createMMKV.mock.d.ts +2 -0
  133. package/lib/typescript/createMMKV.web.d.ts +2 -0
  134. package/lib/typescript/createTextEncoder.d.ts +1 -0
  135. package/lib/typescript/hooks.d.ts +81 -0
  136. package/lib/typescript/index.d.ts +2 -0
  137. package/package.json +168 -0
  138. package/react-native-mmkv.podspec +32 -0
@@ -0,0 +1,537 @@
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
+
21
+ #include "MemoryFile.h"
22
+
23
+ #ifndef MMKV_WIN32
24
+
25
+ # include "InterProcessLock.h"
26
+ # include "MMBuffer.h"
27
+ # include "MMKVLog.h"
28
+ # include "ScopedLock.hpp"
29
+ # include <cerrno>
30
+ # include <utility>
31
+ # include <fcntl.h>
32
+ # include <sys/mman.h>
33
+ # include <sys/stat.h>
34
+ # include <unistd.h>
35
+ # include <sys/file.h>
36
+ # include <dirent.h>
37
+ # include <cstring>
38
+
39
+ using namespace std;
40
+
41
+ namespace mmkv {
42
+
43
+ extern bool getFileSize(int fd, size_t &size);
44
+
45
+ # ifdef MMKV_ANDROID
46
+ extern size_t ASharedMemory_getSize(int fd);
47
+ # else
48
+ File::File(MMKVPath_t path, OpenFlag flag) : m_path(std::move(path)), m_fd(-1), m_flag(flag) {
49
+ open();
50
+ }
51
+
52
+ MemoryFile::MemoryFile(MMKVPath_t path) : m_diskFile(std::move(path), OpenFlag::ReadWrite | OpenFlag::Create), m_ptr(nullptr), m_size(0) {
53
+ reloadFromFile();
54
+ }
55
+ # endif // !defined(MMKV_ANDROID)
56
+
57
+ # ifdef MMKV_IOS
58
+ void tryResetFileProtection(const string &path);
59
+ # endif
60
+
61
+ static int OpenFlag2NativeFlag(OpenFlag flag) {
62
+ int native = O_CLOEXEC;
63
+ if (flag & OpenFlag::ReadWrite) {
64
+ native |= O_RDWR;
65
+ } else if (flag & OpenFlag::ReadOnly) {
66
+ native |= O_RDONLY;
67
+ } else if (flag & OpenFlag::WriteOnly) {
68
+ native |= O_WRONLY;
69
+ }
70
+
71
+ if (flag & OpenFlag::Create) {
72
+ native |= O_CREAT;
73
+ }
74
+ if (flag & OpenFlag::Excel) {
75
+ native |= O_EXCL;
76
+ }
77
+ if (flag & OpenFlag::Truncate) {
78
+ native |= O_TRUNC;
79
+ }
80
+ return native;
81
+ }
82
+
83
+ bool File::open() {
84
+ # ifdef MMKV_ANDROID
85
+ if (m_fileType == MMFILE_TYPE_ASHMEM) {
86
+ return isFileValid();
87
+ }
88
+ # endif
89
+ if (isFileValid()) {
90
+ return true;
91
+ }
92
+ m_fd = ::open(m_path.c_str(), OpenFlag2NativeFlag(m_flag), S_IRWXU);
93
+ if (!isFileValid()) {
94
+ MMKVError("fail to open [%s], %d(%s)", m_path.c_str(), errno, strerror(errno));
95
+ return false;
96
+ }
97
+ MMKVInfo("open fd[%p], %s", m_fd, m_path.c_str());
98
+ return true;
99
+ }
100
+
101
+ void File::close() {
102
+ if (isFileValid()) {
103
+ MMKVInfo("closing fd[%p], %s", m_fd, m_path.c_str());
104
+ if (::close(m_fd) == 0) {
105
+ m_fd = -1;
106
+ } else {
107
+ MMKVError("fail to close [%s], %d(%s)", m_path.c_str(), errno, strerror(errno));
108
+ }
109
+ }
110
+ }
111
+
112
+ size_t File::getActualFileSize() const {
113
+ # ifdef MMKV_ANDROID
114
+ if (m_fileType == MMFILE_TYPE_ASHMEM) {
115
+ return ASharedMemory_getSize(m_fd);
116
+ }
117
+ # endif
118
+ size_t size = 0;
119
+ mmkv::getFileSize(m_fd, size);
120
+ return size;
121
+ }
122
+
123
+ bool MemoryFile::truncate(size_t size) {
124
+ if (!m_diskFile.isFileValid()) {
125
+ return false;
126
+ }
127
+ if (size == m_size) {
128
+ return true;
129
+ }
130
+ # ifdef MMKV_ANDROID
131
+ if (m_diskFile.m_fileType == MMFILE_TYPE_ASHMEM) {
132
+ if (size > m_size) {
133
+ MMKVError("ashmem %s reach size limit:%zu, consider configure with larger size", m_diskFile.m_path.c_str(), m_size);
134
+ } else {
135
+ MMKVInfo("no way to trim ashmem %s from %zu to smaller size %zu", m_diskFile.m_path.c_str(), m_size, size);
136
+ }
137
+ return false;
138
+ }
139
+ # endif // MMKV_ANDROID
140
+
141
+ auto oldSize = m_size;
142
+ m_size = size;
143
+ // round up to (n * pagesize)
144
+ if (m_size < DEFAULT_MMAP_SIZE || (m_size % DEFAULT_MMAP_SIZE != 0)) {
145
+ m_size = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
146
+ }
147
+
148
+ if (::ftruncate(m_diskFile.m_fd, static_cast<off_t>(m_size)) != 0) {
149
+ MMKVError("fail to truncate [%s] to size %zu, %s", m_diskFile.m_path.c_str(), m_size, strerror(errno));
150
+ m_size = oldSize;
151
+ return false;
152
+ }
153
+ if (m_size > oldSize) {
154
+ if (!zeroFillFile(m_diskFile.m_fd, oldSize, m_size - oldSize)) {
155
+ MMKVError("fail to zeroFile [%s] to size %zu, %s", m_diskFile.m_path.c_str(), m_size, strerror(errno));
156
+ m_size = oldSize;
157
+ return false;
158
+ }
159
+ }
160
+
161
+ if (m_ptr) {
162
+ if (munmap(m_ptr, oldSize) != 0) {
163
+ MMKVError("fail to munmap [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
164
+ }
165
+ }
166
+ auto ret = mmap();
167
+ if (!ret) {
168
+ doCleanMemoryCache(true);
169
+ }
170
+ return ret;
171
+ }
172
+
173
+ bool MemoryFile::msync(SyncFlag syncFlag) {
174
+ if (m_ptr) {
175
+ auto ret = ::msync(m_ptr, m_size, syncFlag ? MS_SYNC : MS_ASYNC);
176
+ if (ret == 0) {
177
+ return true;
178
+ }
179
+ MMKVError("fail to msync [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
180
+ }
181
+ return false;
182
+ }
183
+
184
+ bool MemoryFile::mmap() {
185
+ m_ptr = (char *) ::mmap(m_ptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_diskFile.m_fd, 0);
186
+ if (m_ptr == MAP_FAILED) {
187
+ MMKVError("fail to mmap [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
188
+ m_ptr = nullptr;
189
+ return false;
190
+ }
191
+
192
+ return true;
193
+ }
194
+
195
+ void MemoryFile::reloadFromFile() {
196
+ # ifdef MMKV_ANDROID
197
+ if (m_fileType == MMFILE_TYPE_ASHMEM) {
198
+ return;
199
+ }
200
+ # endif
201
+ if (isFileValid()) {
202
+ MMKVWarning("calling reloadFromFile while the cache [%s] is still valid", m_diskFile.m_path.c_str());
203
+ MMKV_ASSERT(0);
204
+ clearMemoryCache();
205
+ }
206
+
207
+ if (!m_diskFile.open()) {
208
+ MMKVError("fail to open:%s, %s", m_diskFile.m_path.c_str(), strerror(errno));
209
+ } else {
210
+ FileLock fileLock(m_diskFile.m_fd);
211
+ InterProcessLock lock(&fileLock, ExclusiveLockType);
212
+ SCOPED_LOCK(&lock);
213
+
214
+ mmkv::getFileSize(m_diskFile.m_fd, m_size);
215
+ // round up to (n * pagesize)
216
+ if (m_size < DEFAULT_MMAP_SIZE || (m_size % DEFAULT_MMAP_SIZE != 0)) {
217
+ size_t roundSize = ((m_size / DEFAULT_MMAP_SIZE) + 1) * DEFAULT_MMAP_SIZE;
218
+ truncate(roundSize);
219
+ } else {
220
+ auto ret = mmap();
221
+ if (!ret) {
222
+ doCleanMemoryCache(true);
223
+ }
224
+ }
225
+ # ifdef MMKV_IOS
226
+ tryResetFileProtection(m_diskFile.m_path);
227
+ # endif
228
+ }
229
+ }
230
+
231
+ void MemoryFile::doCleanMemoryCache(bool forceClean) {
232
+ # ifdef MMKV_ANDROID
233
+ if (m_diskFile.m_fileType == MMFILE_TYPE_ASHMEM && !forceClean) {
234
+ return;
235
+ }
236
+ # endif
237
+ if (m_ptr && m_ptr != MAP_FAILED) {
238
+ if (munmap(m_ptr, m_size) != 0) {
239
+ MMKVError("fail to munmap [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
240
+ }
241
+ }
242
+ m_ptr = nullptr;
243
+
244
+ m_diskFile.close();
245
+ m_size = 0;
246
+ }
247
+
248
+ bool isFileExist(const string &nsFilePath) {
249
+ if (nsFilePath.empty()) {
250
+ return false;
251
+ }
252
+
253
+ struct stat temp = {};
254
+ return lstat(nsFilePath.c_str(), &temp) == 0;
255
+ }
256
+
257
+ extern bool mkPath(const MMKVPath_t &str) {
258
+ char *path = strdup(str.c_str());
259
+
260
+ struct stat sb = {};
261
+ bool done = false;
262
+ char *slash = path;
263
+
264
+ while (!done) {
265
+ slash += strspn(slash, "/");
266
+ slash += strcspn(slash, "/");
267
+
268
+ done = (*slash == '\0');
269
+ *slash = '\0';
270
+
271
+ if (stat(path, &sb) != 0) {
272
+ if (errno != ENOENT || mkdir(path, 0777) != 0) {
273
+ MMKVWarning("%s : %s", path, strerror(errno));
274
+ free(path);
275
+ return false;
276
+ }
277
+ } else if (!S_ISDIR(sb.st_mode)) {
278
+ MMKVWarning("%s: %s", path, strerror(ENOTDIR));
279
+ free(path);
280
+ return false;
281
+ }
282
+
283
+ *slash = '/';
284
+ }
285
+ free(path);
286
+
287
+ return true;
288
+ }
289
+
290
+ MMBuffer *readWholeFile(const MMKVPath_t &path) {
291
+ MMBuffer *buffer = nullptr;
292
+ int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
293
+ if (fd >= 0) {
294
+ auto fileLength = lseek(fd, 0, SEEK_END);
295
+ if (fileLength > 0) {
296
+ buffer = new MMBuffer(static_cast<size_t>(fileLength));
297
+ lseek(fd, 0, SEEK_SET);
298
+ auto readSize = read(fd, buffer->getPtr(), static_cast<size_t>(fileLength));
299
+ if (readSize != -1) {
300
+ //fileSize = readSize;
301
+ } else {
302
+ MMKVWarning("fail to read %s: %s", path.c_str(), strerror(errno));
303
+
304
+ delete buffer;
305
+ buffer = nullptr;
306
+ }
307
+ }
308
+ close(fd);
309
+ } else {
310
+ MMKVWarning("fail to open %s: %s", path.c_str(), strerror(errno));
311
+ }
312
+ return buffer;
313
+ }
314
+
315
+ bool zeroFillFile(int fd, size_t startPos, size_t size) {
316
+ if (fd < 0) {
317
+ return false;
318
+ }
319
+
320
+ if (lseek(fd, static_cast<off_t>(startPos), SEEK_SET) < 0) {
321
+ MMKVError("fail to lseek fd[%d], error:%s", fd, strerror(errno));
322
+ return false;
323
+ }
324
+
325
+ static const char zeros[4096] = {};
326
+ while (size >= sizeof(zeros)) {
327
+ if (write(fd, zeros, sizeof(zeros)) < 0) {
328
+ MMKVError("fail to write fd[%d], error:%s", fd, strerror(errno));
329
+ return false;
330
+ }
331
+ size -= sizeof(zeros);
332
+ }
333
+ if (size > 0) {
334
+ if (write(fd, zeros, size) < 0) {
335
+ MMKVError("fail to write fd[%d], error:%s", fd, strerror(errno));
336
+ return false;
337
+ }
338
+ }
339
+ return true;
340
+ }
341
+
342
+ bool getFileSize(int fd, size_t &size) {
343
+ struct stat st = {};
344
+ if (fstat(fd, &st) != -1) {
345
+ size = (size_t) st.st_size;
346
+ return true;
347
+ }
348
+ return false;
349
+ }
350
+
351
+ size_t getPageSize() {
352
+ return static_cast<size_t>(getpagesize());
353
+ }
354
+
355
+ #ifndef MMKV_APPLE
356
+
357
+ static pair<MMKVPath_t, int> createUniqueTempFile(const char *prefix) {
358
+ char path[PATH_MAX];
359
+ #ifdef MMKV_ANDROID
360
+ snprintf(path, PATH_MAX, "%s/%s.XXXXXX", g_android_tmpDir.c_str(), prefix);
361
+ #else
362
+ snprintf(path, PATH_MAX, "%s/%s.XXXXXX", P_tmpdir, prefix);
363
+ #endif
364
+
365
+ auto fd = mkstemp(path);
366
+ if (fd < 0) {
367
+ MMKVError("fail to create unique temp file [%s], %d(%s)", path, errno, strerror(errno));
368
+ return {"", fd};
369
+ }
370
+ MMKVDebug("create unique temp file [%s] with fd[%d]", path, fd);
371
+ return {MMKVPath_t(path), fd};
372
+ }
373
+
374
+ #if !defined(MMKV_ANDROID) && !defined(MMKV_LINUX)
375
+
376
+ bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
377
+ if (::rename(srcPath.c_str(), dstPath.c_str()) != 0) {
378
+ MMKVError("fail to rename [%s] to [%s], %d(%s)", srcPath.c_str(), dstPath.c_str(), errno, strerror(errno));
379
+ return false;
380
+ }
381
+ return true;
382
+ }
383
+
384
+ bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool needTruncate) {
385
+ if (dstFD < 0) {
386
+ return false;
387
+ }
388
+ bool ret = false;
389
+ File srcFile(srcPath, OpenFlag::ReadOnly);
390
+ if (!srcFile.isFileValid()) {
391
+ return false;
392
+ }
393
+ auto bufferSize = getPageSize();
394
+ auto buffer = (char *) malloc(bufferSize);
395
+ if (!buffer) {
396
+ MMKVError("fail to malloc size %zu, %d(%s)", bufferSize, errno, strerror(errno));
397
+ goto errorOut;
398
+ }
399
+ lseek(dstFD, 0, SEEK_SET);
400
+
401
+ // the POSIX standard don't have sendfile()/fcopyfile() equivalent, do it the hard way
402
+ while (true) {
403
+ auto sizeRead = read(srcFile.getFd(), buffer, bufferSize);
404
+ if (sizeRead < 0) {
405
+ MMKVError("fail to read file [%s], %d(%s)", srcPath.c_str(), errno, strerror(errno));
406
+ goto errorOut;
407
+ }
408
+
409
+ size_t totalWrite = 0;
410
+ do {
411
+ auto sizeWrite = write(dstFD, buffer + totalWrite, sizeRead - totalWrite);
412
+ if (sizeWrite < 0) {
413
+ MMKVError("fail to write fd [%d], %d(%s)", dstFD, errno, strerror(errno));
414
+ goto errorOut;
415
+ }
416
+ totalWrite += sizeWrite;
417
+ } while (totalWrite < sizeRead);
418
+
419
+ if (sizeRead < bufferSize) {
420
+ break;
421
+ }
422
+ }
423
+ if (needTruncate) {
424
+ size_t dstFileSize = 0;
425
+ getFileSize(dstFD, dstFileSize);
426
+ auto srcFileSize = srcFile.getActualFileSize();
427
+ if ((dstFileSize != srcFileSize) && (::ftruncate(dstFD, static_cast<off_t>(srcFileSize)) != 0)) {
428
+ MMKVError("fail to truncate [%d] to size [%zu], %d(%s)", dstFD, srcFileSize, errno, strerror(errno));
429
+ goto errorOut;
430
+ }
431
+ }
432
+
433
+ ret = true;
434
+ MMKVInfo("copy content from %s to fd[%d] finish", srcPath.c_str(), dstFD);
435
+
436
+ errorOut:
437
+ free(buffer);
438
+ return ret;
439
+ }
440
+
441
+ #endif // !defined(MMKV_ANDROID) && !defined(MMKV_LINUX)
442
+
443
+ // copy to a temp file then rename it
444
+ // this is the best we can do under the POSIX standard
445
+ bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
446
+ auto pair = createUniqueTempFile("MMKV");
447
+ auto tmpFD = pair.second;
448
+ auto &tmpPath = pair.first;
449
+ if (tmpFD < 0) {
450
+ return false;
451
+ }
452
+
453
+ bool renamed = false;
454
+ if (copyFileContent(srcPath, tmpFD, false)) {
455
+ MMKVInfo("copyfile [%s] to [%s]", srcPath.c_str(), tmpPath.c_str());
456
+ renamed = tryAtomicRename(tmpPath, dstPath);
457
+ if (renamed) {
458
+ MMKVInfo("copyfile [%s] to [%s] finish.", srcPath.c_str(), dstPath.c_str());
459
+ }
460
+ }
461
+
462
+ ::close(tmpFD);
463
+ if (!renamed) {
464
+ ::unlink(tmpPath.c_str());
465
+ }
466
+ return renamed;
467
+ }
468
+
469
+ bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
470
+ File dstFile(dstPath, OpenFlag::WriteOnly | OpenFlag::Create | OpenFlag::Truncate);
471
+ if (!dstFile.isFileValid()) {
472
+ return false;
473
+ }
474
+ auto ret = copyFileContent(srcPath, dstFile.getFd(), false);
475
+ if (!ret) {
476
+ MMKVError("fail to copyfile(): target file %s", dstPath.c_str());
477
+ } else {
478
+ MMKVInfo("copy content from %s to [%s] finish", srcPath.c_str(), dstPath.c_str());
479
+ }
480
+ return ret;
481
+ }
482
+
483
+ bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD) {
484
+ return copyFileContent(srcPath, dstFD, true);
485
+ }
486
+
487
+ #endif // !defined(MMKV_APPLE)
488
+
489
+ void walkInDir(const MMKVPath_t &dirPath, WalkType type, const function<void(const MMKVPath_t&, WalkType)> &walker) {
490
+ auto folderPathStr = dirPath.data();
491
+ DIR *dir = opendir(folderPathStr);
492
+ if (!dir) {
493
+ MMKVError("opendir failed: %d(%s), %s", errno, strerror(errno), dirPath.c_str());
494
+ return;
495
+ }
496
+
497
+ char childPath[PATH_MAX];
498
+ size_t folderPathLength = dirPath.size();
499
+ strncpy(childPath, folderPathStr, folderPathLength + 1);
500
+ if (folderPathStr[folderPathLength - 1] != '/') {
501
+ childPath[folderPathLength] = '/';
502
+ folderPathLength++;
503
+ }
504
+
505
+ while (auto child = readdir(dir)) {
506
+ if ((child->d_type & DT_REG) && (type & WalkFile)) {
507
+ #ifdef _DIRENT_HAVE_D_NAMLEN
508
+ stpcpy(childPath + folderPathLength, child->d_name);
509
+ childPath[folderPathLength + child->d_namlen] = 0;
510
+ #else
511
+ strcpy(childPath + folderPathLength, child->d_name);
512
+ #endif
513
+ walker(childPath, WalkFile);
514
+ } else if ((child->d_type & DT_DIR) && (type & WalkFolder)) {
515
+ #ifdef _DIRENT_HAVE_D_NAMLEN
516
+ if ((child->d_namlen == 1 && child->d_name[0] == '.') ||
517
+ (child->d_namlen == 2 && child->d_name[0] == '.' && child->d_name[1] == '.')) {
518
+ continue;
519
+ }
520
+ stpcpy(childPath + folderPathLength, child->d_name);
521
+ childPath[folderPathLength + child->d_namlen] = 0;
522
+ #else
523
+ if (strcmp(child->d_name, ".") == 0 || strcmp(child->d_name, "..") == 0) {
524
+ continue;
525
+ }
526
+ strcpy(childPath + folderPathLength, child->d_name);
527
+ #endif
528
+ walker(childPath, WalkFolder);
529
+ }
530
+ }
531
+
532
+ closedir(dir);
533
+ }
534
+
535
+ } // namespace mmkv
536
+
537
+ #endif // !defined(MMKV_WIN32)
@@ -0,0 +1,182 @@
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
+
21
+ #ifndef MMKV_MAMERYFILE_H
22
+ #define MMKV_MAMERYFILE_H
23
+ #ifdef __cplusplus
24
+
25
+ #include "MMKVPredef.h"
26
+ #include <functional>
27
+
28
+ #ifdef MMKV_ANDROID
29
+ MMKVPath_t ashmemMMKVPathWithID(const MMKVPath_t &mmapID);
30
+
31
+ namespace mmkv {
32
+ extern int g_android_api;
33
+ extern std::string g_android_tmpDir;
34
+
35
+ enum FileType : bool { MMFILE_TYPE_FILE = false, MMFILE_TYPE_ASHMEM = true };
36
+ } // namespace mmkv
37
+ #endif // MMKV_ANDROID
38
+
39
+ namespace mmkv {
40
+
41
+ enum class OpenFlag : uint32_t {
42
+ ReadOnly = 1 << 0,
43
+ WriteOnly = 1 << 1,
44
+ ReadWrite = ReadOnly | WriteOnly,
45
+ Create = 1 << 2,
46
+ Excel = 1 << 3, // fail if Create is set but the file already exist
47
+ Truncate = 1 << 4,
48
+ };
49
+
50
+ static inline OpenFlag operator | (OpenFlag left, OpenFlag right) {
51
+ return static_cast<OpenFlag>(static_cast<uint32_t>(left) | static_cast<uint32_t>(right));
52
+ }
53
+
54
+ static inline bool operator & (OpenFlag left, OpenFlag right) {
55
+ return ((static_cast<uint32_t>(left) & static_cast<uint32_t>(right)) != 0);
56
+ }
57
+
58
+ class File {
59
+ MMKVPath_t m_path;
60
+ MMKVFileHandle_t m_fd;
61
+ public:
62
+ const OpenFlag m_flag;
63
+ #ifndef MMKV_ANDROID
64
+ explicit File(MMKVPath_t path, OpenFlag flag);
65
+ #else
66
+ File(MMKVPath_t path, OpenFlag flag, size_t size = 0, FileType fileType = MMFILE_TYPE_FILE);
67
+ explicit File(MMKVFileHandle_t ashmemFD);
68
+
69
+ size_t m_size;
70
+ const FileType m_fileType;
71
+ #endif // MMKV_ANDROID
72
+
73
+ ~File() { close(); }
74
+
75
+ bool open();
76
+
77
+ void close();
78
+
79
+ MMKVFileHandle_t getFd() { return m_fd; }
80
+
81
+ const MMKVPath_t &getPath() const { return m_path; }
82
+
83
+ #ifndef MMKV_WIN32
84
+ bool isFileValid() const { return m_fd >= 0; }
85
+ #else
86
+ bool isFileValid() const { return m_fd != INVALID_HANDLE_VALUE; }
87
+ #endif
88
+
89
+ // get the actual file size on disk
90
+ size_t getActualFileSize() const;
91
+
92
+ // just forbid it for possibly misuse
93
+ explicit File(const File &other) = delete;
94
+ File &operator=(const File &other) = delete;
95
+
96
+ friend class MemoryFile;
97
+ };
98
+
99
+ class MemoryFile {
100
+ File m_diskFile;
101
+ #ifdef MMKV_WIN32
102
+ HANDLE m_fileMapping;
103
+ #endif
104
+ void *m_ptr;
105
+ size_t m_size;
106
+
107
+ bool mmap();
108
+
109
+ void doCleanMemoryCache(bool forceClean);
110
+
111
+ public:
112
+ #ifndef MMKV_ANDROID
113
+ explicit MemoryFile(MMKVPath_t path);
114
+ #else
115
+ MemoryFile(MMKVPath_t path, size_t size, FileType fileType);
116
+ explicit MemoryFile(MMKVFileHandle_t ashmemFD);
117
+
118
+ const FileType m_fileType;
119
+ #endif // MMKV_ANDROID
120
+
121
+ ~MemoryFile() { doCleanMemoryCache(true); }
122
+
123
+ size_t getFileSize() const { return m_size; }
124
+
125
+ // get the actual file size on disk
126
+ size_t getActualFileSize() const { return m_diskFile.getActualFileSize(); }
127
+
128
+ void *getMemory() { return m_ptr; }
129
+
130
+ const MMKVPath_t &getPath() { return m_diskFile.getPath(); }
131
+
132
+ MMKVFileHandle_t getFd() { return m_diskFile.getFd(); }
133
+
134
+ // the newly expanded file content will be zeroed
135
+ bool truncate(size_t size);
136
+
137
+ bool msync(SyncFlag syncFlag);
138
+
139
+ // call this if clearMemoryCache() has been called
140
+ void reloadFromFile();
141
+
142
+ void clearMemoryCache() { doCleanMemoryCache(false); }
143
+
144
+ #ifndef MMKV_WIN32
145
+ bool isFileValid() { return m_diskFile.isFileValid() && m_size > 0 && m_ptr; }
146
+ #else
147
+ bool isFileValid() { return m_diskFile.isFileValid() && m_size > 0 && m_fileMapping && m_ptr; }
148
+ #endif
149
+
150
+ // just forbid it for possibly misuse
151
+ explicit MemoryFile(const MemoryFile &other) = delete;
152
+ MemoryFile &operator=(const MemoryFile &other) = delete;
153
+ };
154
+
155
+ class MMBuffer;
156
+
157
+ extern bool mkPath(const MMKVPath_t &path);
158
+ extern bool isFileExist(const MMKVPath_t &nsFilePath);
159
+ extern MMBuffer *readWholeFile(const MMKVPath_t &path);
160
+ extern bool zeroFillFile(MMKVFileHandle_t fd, size_t startPos, size_t size);
161
+ extern size_t getPageSize();
162
+
163
+ extern bool tryAtomicRename(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath);
164
+
165
+ // copy file by potentially renaming target file, might change file inode
166
+ extern bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath);
167
+
168
+ // copy file by source file content, keep file inode the same
169
+ extern bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath);
170
+ extern bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD);
171
+ extern bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool needTruncate);
172
+
173
+ enum WalkType : uint32_t {
174
+ WalkFile = 1 << 0,
175
+ WalkFolder = 1 << 1,
176
+ };
177
+ extern void walkInDir(const MMKVPath_t &dirPath, WalkType type, const std::function<void(const MMKVPath_t&, WalkType)> &walker);
178
+
179
+ } // namespace mmkv
180
+
181
+ #endif
182
+ #endif //MMKV_MAMERYFILE_H