react-native-mmkv 3.0.2 → 3.2.0
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.
- package/MMKV/Core/MMKV.cpp +51 -15
- package/MMKV/Core/MMKV.h +19 -5
- package/MMKV/Core/MMKVPredef.h +2 -2
- package/MMKV/Core/MMKV_Android.cpp +13 -13
- package/MMKV/Core/MMKV_IO.cpp +37 -6
- package/MMKV/Core/MMKV_OSX.cpp +15 -4
- package/MMKV/Core/MemoryFile.cpp +24 -10
- package/MMKV/Core/MemoryFile.h +8 -2
- package/MMKV/Core/MemoryFile_Android.cpp +4 -3
- package/MMKV/Core/MemoryFile_Win32.cpp +22 -11
- package/MMKV/Core/aes/AESCrypt.cpp +19 -24
- package/MMKV/Core/aes/AESCrypt.h +4 -1
- package/MMKV/README.md +354 -0
- package/README.md +5 -0
- package/cpp/MmkvHostObject.cpp +18 -3
- package/cpp/NativeMmkvModule.h +1 -1
- package/lib/commonjs/MMKV.js +5 -5
- package/lib/commonjs/MMKV.js.map +1 -1
- package/lib/commonjs/MemoryWarningListener.js +31 -0
- package/lib/commonjs/MemoryWarningListener.js.map +1 -0
- package/lib/commonjs/MemoryWarningListener.web.js +11 -0
- package/lib/commonjs/MemoryWarningListener.web.js.map +1 -0
- package/lib/commonjs/NativeMmkv.js +10 -5
- package/lib/commonjs/NativeMmkv.js.map +1 -1
- package/lib/commonjs/NativeMmkvPlatformContext.js +4 -4
- package/lib/commonjs/NativeMmkvPlatformContext.js.map +1 -1
- package/lib/commonjs/Types.js +24 -0
- package/lib/commonjs/Types.js.map +1 -1
- package/lib/commonjs/createMMKV.js +7 -0
- package/lib/commonjs/createMMKV.js.map +1 -1
- package/lib/commonjs/createMMKV.mock.js +1 -0
- package/lib/commonjs/createMMKV.mock.js.map +1 -1
- package/lib/commonjs/createMMKV.web.js +1 -0
- package/lib/commonjs/createMMKV.web.js.map +1 -1
- package/lib/commonjs/index.js +3 -10
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/MMKV.js +5 -5
- package/lib/module/MMKV.js.map +1 -1
- package/lib/module/MemoryWarningListener.js +27 -0
- package/lib/module/MemoryWarningListener.js.map +1 -0
- package/lib/module/MemoryWarningListener.web.js +6 -0
- package/lib/module/MemoryWarningListener.web.js.map +1 -0
- package/lib/module/NativeMmkv.js +10 -5
- package/lib/module/NativeMmkv.js.map +1 -1
- package/lib/module/NativeMmkvPlatformContext.js +4 -4
- package/lib/module/NativeMmkvPlatformContext.js.map +1 -1
- package/lib/module/Types.js +23 -0
- package/lib/module/Types.js.map +1 -1
- package/lib/module/createMMKV.js +7 -0
- package/lib/module/createMMKV.js.map +1 -1
- package/lib/module/createMMKV.mock.js +1 -0
- package/lib/module/createMMKV.mock.js.map +1 -1
- package/lib/module/createMMKV.web.js +1 -0
- package/lib/module/createMMKV.web.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/MMKV.d.ts +2 -2
- package/lib/typescript/src/MMKV.d.ts.map +1 -1
- package/lib/typescript/src/MemoryWarningListener.d.ts +3 -0
- package/lib/typescript/src/MemoryWarningListener.d.ts.map +1 -0
- package/lib/typescript/src/MemoryWarningListener.web.d.ts +3 -0
- package/lib/typescript/src/MemoryWarningListener.web.d.ts.map +1 -0
- package/lib/typescript/src/NativeMmkv.d.ts +9 -0
- package/lib/typescript/src/NativeMmkv.d.ts.map +1 -1
- package/lib/typescript/src/NativeMmkvPlatformContext.d.ts.map +1 -1
- package/lib/typescript/src/Types.d.ts +76 -0
- package/lib/typescript/src/Types.d.ts.map +1 -1
- package/lib/typescript/src/createMMKV.d.ts +1 -2
- package/lib/typescript/src/createMMKV.d.ts.map +1 -1
- package/lib/typescript/src/createMMKV.mock.d.ts.map +1 -1
- package/lib/typescript/src/createMMKV.web.d.ts +1 -2
- package/lib/typescript/src/createMMKV.web.d.ts.map +1 -1
- package/lib/typescript/src/hooks.d.ts +1 -1
- package/lib/typescript/src/hooks.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +12 -14
- package/react-native-mmkv.podspec +1 -1
- package/src/MMKV.ts +11 -7
- package/src/MemoryWarningListener.ts +29 -0
- package/src/MemoryWarningListener.web.ts +5 -0
- package/src/NativeMmkv.ts +14 -5
- package/src/NativeMmkvPlatformContext.ts +6 -4
- package/src/Types.ts +79 -0
- package/src/createMMKV.mock.ts +1 -0
- package/src/createMMKV.ts +9 -2
- package/src/createMMKV.web.ts +2 -2
- package/src/hooks.ts +1 -1
- package/src/index.ts +1 -1
- package/img/banner-dark.png +0 -0
- package/img/banner-light.png +0 -0
package/MMKV/Core/MMKV.cpp
CHANGED
|
@@ -80,20 +80,21 @@ MMKVPath_t filename(const MMKVPath_t &path);
|
|
|
80
80
|
#ifndef MMKV_ANDROID
|
|
81
81
|
MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath, size_t expectedCapacity)
|
|
82
82
|
: m_mmapID(mmapID)
|
|
83
|
+
, m_mode(mode)
|
|
83
84
|
, m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
|
|
84
85
|
, m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
|
|
85
86
|
, m_dic(nullptr)
|
|
86
87
|
, m_dicCrypt(nullptr)
|
|
87
88
|
, m_expectedCapacity(std::max<size_t>(DEFAULT_MMAP_SIZE, roundUp<size_t>(expectedCapacity, DEFAULT_MMAP_SIZE)))
|
|
88
|
-
, m_file(new MemoryFile(m_path, m_expectedCapacity))
|
|
89
|
-
, m_metaFile(new MemoryFile(m_crcPath))
|
|
89
|
+
, m_file(new MemoryFile(m_path, m_expectedCapacity, isReadOnly()))
|
|
90
|
+
, m_metaFile(new MemoryFile(m_crcPath, 0, isReadOnly()))
|
|
90
91
|
, m_metaInfo(new MMKVMetaInfo())
|
|
91
92
|
, m_crypter(nullptr)
|
|
92
93
|
, m_lock(new ThreadLock())
|
|
93
94
|
, m_fileLock(new FileLock(m_metaFile->getFd()))
|
|
94
95
|
, m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
|
|
95
96
|
, m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
|
|
96
|
-
|
|
97
|
+
{
|
|
97
98
|
m_actualSize = 0;
|
|
98
99
|
m_output = nullptr;
|
|
99
100
|
|
|
@@ -114,8 +115,8 @@ MMKV::MMKV(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *ro
|
|
|
114
115
|
m_crcDigest = 0;
|
|
115
116
|
|
|
116
117
|
m_lock->initialize();
|
|
117
|
-
m_sharedProcessLock->m_enable =
|
|
118
|
-
m_exclusiveProcessLock->m_enable =
|
|
118
|
+
m_sharedProcessLock->m_enable = isMultiProcess();
|
|
119
|
+
m_exclusiveProcessLock->m_enable = isMultiProcess();
|
|
119
120
|
|
|
120
121
|
// sensitive zone
|
|
121
122
|
/*{
|
|
@@ -219,8 +220,10 @@ void MMKV::initializeMMKV(const MMKVPath_t &rootDir, MMKVLogLevel logLevel, mmkv
|
|
|
219
220
|
# endif
|
|
220
221
|
#endif
|
|
221
222
|
|
|
222
|
-
g_rootDir
|
|
223
|
-
|
|
223
|
+
if (g_rootDir.empty()) {
|
|
224
|
+
g_rootDir = rootDir;
|
|
225
|
+
mkPath(g_rootDir);
|
|
226
|
+
}
|
|
224
227
|
|
|
225
228
|
MMKVInfo("root dir: " MMKV_PATH_FORMAT, g_rootDir.c_str());
|
|
226
229
|
}
|
|
@@ -232,7 +235,7 @@ const MMKVPath_t &MMKV::getRootDir() {
|
|
|
232
235
|
#ifndef MMKV_ANDROID
|
|
233
236
|
MMKV *MMKV::mmkvWithID(const string &mmapID, MMKVMode mode, string *cryptKey, MMKVPath_t *rootPath, size_t expectedCapacity) {
|
|
234
237
|
|
|
235
|
-
if (mmapID.empty()) {
|
|
238
|
+
if (mmapID.empty() || !g_instanceLock) {
|
|
236
239
|
return nullptr;
|
|
237
240
|
}
|
|
238
241
|
SCOPED_LOCK(g_instanceLock);
|
|
@@ -260,6 +263,9 @@ MMKV *MMKV::mmkvWithID(const string &mmapID, MMKVMode mode, string *cryptKey, MM
|
|
|
260
263
|
#endif
|
|
261
264
|
|
|
262
265
|
void MMKV::onExit() {
|
|
266
|
+
if (!g_instanceLock) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
263
269
|
SCOPED_LOCK(g_instanceLock);
|
|
264
270
|
|
|
265
271
|
for (auto &pair : *g_instanceDic) {
|
|
@@ -1094,15 +1100,19 @@ size_t MMKV::actualSize() {
|
|
|
1094
1100
|
return m_actualSize;
|
|
1095
1101
|
}
|
|
1096
1102
|
|
|
1097
|
-
|
|
1103
|
+
bool MMKV::removeValueForKey(MMKVKey_t key) {
|
|
1098
1104
|
if (isKeyEmpty(key)) {
|
|
1099
|
-
return;
|
|
1105
|
+
return false;
|
|
1106
|
+
}
|
|
1107
|
+
if (isReadOnly()) {
|
|
1108
|
+
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1109
|
+
return false;
|
|
1100
1110
|
}
|
|
1101
1111
|
SCOPED_LOCK(m_lock);
|
|
1102
1112
|
SCOPED_LOCK(m_exclusiveProcessLock);
|
|
1103
1113
|
checkLoadData();
|
|
1104
1114
|
|
|
1105
|
-
removeDataForKey(key);
|
|
1115
|
+
return removeDataForKey(key);
|
|
1106
1116
|
}
|
|
1107
1117
|
|
|
1108
1118
|
#ifndef MMKV_APPLE
|
|
@@ -1129,9 +1139,13 @@ vector<string> MMKV::allKeys(bool filterExpire) {
|
|
|
1129
1139
|
return keys;
|
|
1130
1140
|
}
|
|
1131
1141
|
|
|
1132
|
-
|
|
1142
|
+
bool MMKV::removeValuesForKeys(const vector<string> &arrKeys) {
|
|
1143
|
+
if (isReadOnly()) {
|
|
1144
|
+
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1145
|
+
return false;
|
|
1146
|
+
}
|
|
1133
1147
|
if (arrKeys.empty()) {
|
|
1134
|
-
return;
|
|
1148
|
+
return true;
|
|
1135
1149
|
}
|
|
1136
1150
|
if (arrKeys.size() == 1) {
|
|
1137
1151
|
return removeValueForKey(arrKeys[0]);
|
|
@@ -1162,8 +1176,9 @@ void MMKV::removeValuesForKeys(const vector<string> &arrKeys) {
|
|
|
1162
1176
|
if (deleteCount > 0) {
|
|
1163
1177
|
m_hasFullWriteback = false;
|
|
1164
1178
|
|
|
1165
|
-
fullWriteback();
|
|
1179
|
+
return fullWriteback();
|
|
1166
1180
|
}
|
|
1181
|
+
return true;
|
|
1167
1182
|
}
|
|
1168
1183
|
|
|
1169
1184
|
#endif // MMKV_APPLE
|
|
@@ -1238,6 +1253,9 @@ static bool backupOneToDirectoryByFilePath(const string &mmapKey, const MMKVPath
|
|
|
1238
1253
|
}
|
|
1239
1254
|
|
|
1240
1255
|
bool MMKV::backupOneToDirectory(const string &mmapKey, const MMKVPath_t &dstPath, const MMKVPath_t &srcPath, bool compareFullPath) {
|
|
1256
|
+
if (!g_instanceLock) {
|
|
1257
|
+
return false;
|
|
1258
|
+
}
|
|
1241
1259
|
// we have to lock the creation of MMKV instance, regardless of in cache or not
|
|
1242
1260
|
SCOPED_LOCK(g_instanceLock);
|
|
1243
1261
|
MMKV *kv = nullptr;
|
|
@@ -1400,6 +1418,9 @@ static bool restoreOneFromDirectoryByFilePath(const string &mmapKey, const MMKVP
|
|
|
1400
1418
|
// They won't know a difference when the file has been replaced.
|
|
1401
1419
|
// We have to let them know by overriding the existing file with new content.
|
|
1402
1420
|
bool MMKV::restoreOneFromDirectory(const string &mmapKey, const MMKVPath_t &srcPath, const MMKVPath_t &dstPath, bool compareFullPath) {
|
|
1421
|
+
if (!g_instanceLock) {
|
|
1422
|
+
return false;
|
|
1423
|
+
}
|
|
1403
1424
|
// we have to lock the creation of MMKV instance, regardless of in cache or not
|
|
1404
1425
|
SCOPED_LOCK(g_instanceLock);
|
|
1405
1426
|
MMKV *kv = nullptr;
|
|
@@ -1447,7 +1468,7 @@ bool MMKV::restoreOneFromDirectory(const string &mmapKey, const MMKVPath_t &srcP
|
|
|
1447
1468
|
// reload data after restore
|
|
1448
1469
|
kv->clearMemoryCache();
|
|
1449
1470
|
kv->loadFromFile();
|
|
1450
|
-
if (kv->
|
|
1471
|
+
if (kv->isMultiProcess()) {
|
|
1451
1472
|
kv->notifyContentChanged();
|
|
1452
1473
|
}
|
|
1453
1474
|
|
|
@@ -1534,26 +1555,41 @@ size_t MMKV::restoreAllFromDirectory(const MMKVPath_t &srcDir, const MMKVPath_t
|
|
|
1534
1555
|
// callbacks
|
|
1535
1556
|
|
|
1536
1557
|
void MMKV::registerErrorHandler(ErrorHandler handler) {
|
|
1558
|
+
if (!g_instanceLock) {
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1537
1561
|
SCOPED_LOCK(g_instanceLock);
|
|
1538
1562
|
g_errorHandler = handler;
|
|
1539
1563
|
}
|
|
1540
1564
|
|
|
1541
1565
|
void MMKV::unRegisterErrorHandler() {
|
|
1566
|
+
if (!g_instanceLock) {
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1542
1569
|
SCOPED_LOCK(g_instanceLock);
|
|
1543
1570
|
g_errorHandler = nullptr;
|
|
1544
1571
|
}
|
|
1545
1572
|
|
|
1546
1573
|
void MMKV::registerLogHandler(LogHandler handler) {
|
|
1574
|
+
if (!g_instanceLock) {
|
|
1575
|
+
return;
|
|
1576
|
+
}
|
|
1547
1577
|
SCOPED_LOCK(g_instanceLock);
|
|
1548
1578
|
g_logHandler = handler;
|
|
1549
1579
|
}
|
|
1550
1580
|
|
|
1551
1581
|
void MMKV::unRegisterLogHandler() {
|
|
1582
|
+
if (!g_instanceLock) {
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1552
1585
|
SCOPED_LOCK(g_instanceLock);
|
|
1553
1586
|
g_logHandler = nullptr;
|
|
1554
1587
|
}
|
|
1555
1588
|
|
|
1556
1589
|
void MMKV::setLogLevel(MMKVLogLevel level) {
|
|
1590
|
+
if (!g_instanceLock) {
|
|
1591
|
+
return;
|
|
1592
|
+
}
|
|
1557
1593
|
SCOPED_LOCK(g_instanceLock);
|
|
1558
1594
|
g_currentLogLevel = level;
|
|
1559
1595
|
}
|
package/MMKV/Core/MMKV.h
CHANGED
|
@@ -58,8 +58,13 @@ enum MMKVMode : uint32_t {
|
|
|
58
58
|
MMKV_ASHMEM = 1 << 3,
|
|
59
59
|
MMKV_BACKUP = 1 << 4,
|
|
60
60
|
#endif
|
|
61
|
+
MMKV_READ_ONLY = 1 << 5,
|
|
61
62
|
};
|
|
62
63
|
|
|
64
|
+
static inline MMKVMode operator | (MMKVMode one, MMKVMode other) {
|
|
65
|
+
return static_cast<MMKVMode>(static_cast<uint32_t>(one) | static_cast<uint32_t>(other));
|
|
66
|
+
}
|
|
67
|
+
|
|
63
68
|
#define MMKV_OUT
|
|
64
69
|
|
|
65
70
|
#ifdef MMKV_HAS_CPP20
|
|
@@ -105,6 +110,7 @@ class MMKV {
|
|
|
105
110
|
~MMKV();
|
|
106
111
|
|
|
107
112
|
std::string m_mmapID;
|
|
113
|
+
const MMKVMode m_mode;
|
|
108
114
|
MMKVPath_t m_path;
|
|
109
115
|
MMKVPath_t m_crcPath;
|
|
110
116
|
mmkv::MMKVMap *m_dic;
|
|
@@ -281,8 +287,16 @@ public:
|
|
|
281
287
|
static void onExit();
|
|
282
288
|
|
|
283
289
|
const std::string &mmapID() const;
|
|
284
|
-
|
|
285
|
-
const
|
|
290
|
+
#ifndef MMKV_ANDROID
|
|
291
|
+
bool isMultiProcess() const { return (m_mode & MMKV_MULTI_PROCESS) != 0; }
|
|
292
|
+
#else
|
|
293
|
+
bool isMultiProcess() const {
|
|
294
|
+
return (m_mode & MMKV_MULTI_PROCESS) != 0
|
|
295
|
+
|| (m_mode & CONTEXT_MODE_MULTI_PROCESS) != 0
|
|
296
|
+
|| (m_mode & MMKV_ASHMEM) != 0; // ashmem is always multi-process
|
|
297
|
+
}
|
|
298
|
+
#endif
|
|
299
|
+
bool isReadOnly() const { return (m_mode & MMKV_READ_ONLY) != 0; }
|
|
286
300
|
|
|
287
301
|
#ifndef MMKV_DISABLE_CRYPT
|
|
288
302
|
std::string cryptKey() const;
|
|
@@ -428,7 +442,7 @@ public:
|
|
|
428
442
|
// filterExpire: return all non-expired keys, keep in mind it comes with cost
|
|
429
443
|
NSArray *allKeys(bool filterExpire = false);
|
|
430
444
|
|
|
431
|
-
|
|
445
|
+
bool removeValuesForKeys(NSArray *arrKeys);
|
|
432
446
|
|
|
433
447
|
typedef void (^EnumerateBlock)(NSString *key, BOOL *stop);
|
|
434
448
|
void enumerateKeys(EnumerateBlock block);
|
|
@@ -441,10 +455,10 @@ public:
|
|
|
441
455
|
// filterExpire: return all non-expired keys, keep in mind it comes with cost
|
|
442
456
|
std::vector<std::string> allKeys(bool filterExpire = false);
|
|
443
457
|
|
|
444
|
-
|
|
458
|
+
bool removeValuesForKeys(const std::vector<std::string> &arrKeys);
|
|
445
459
|
#endif // MMKV_APPLE
|
|
446
460
|
|
|
447
|
-
|
|
461
|
+
bool removeValueForKey(MMKVKey_t key);
|
|
448
462
|
|
|
449
463
|
// keepSpace: remove all keys but keep the file size not changed, running faster
|
|
450
464
|
void clearAll(bool keepSpace = false);
|
package/MMKV/Core/MMKVPredef.h
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
#define MMKV_SRC_MMKVPREDEF_H
|
|
23
23
|
|
|
24
24
|
// disable encryption & decryption to reduce some code
|
|
25
|
-
|
|
25
|
+
// #define MMKV_DISABLE_CRYPT
|
|
26
26
|
//#define MMKV_DISABLE_FLUTTER
|
|
27
27
|
|
|
28
28
|
// using POSIX implementation
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
#include <vector>
|
|
35
35
|
#include <unordered_map>
|
|
36
36
|
|
|
37
|
-
constexpr auto MMKV_VERSION = "
|
|
37
|
+
constexpr auto MMKV_VERSION = "v2.0.0";
|
|
38
38
|
|
|
39
39
|
#ifdef DEBUG
|
|
40
40
|
# define MMKV_DEBUG
|
|
@@ -41,20 +41,20 @@ extern ThreadLock *g_instanceLock;
|
|
|
41
41
|
|
|
42
42
|
MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath, size_t expectedCapacity)
|
|
43
43
|
: m_mmapID((mode & MMKV_BACKUP) ? mmapID : mmapedKVKey(mmapID, rootPath)) // historically Android mistakenly use mmapKey as mmapID
|
|
44
|
+
, m_mode(mode)
|
|
44
45
|
, m_path(mappedKVPathWithID(m_mmapID, mode, rootPath))
|
|
45
46
|
, m_crcPath(crcPathWithID(m_mmapID, mode, rootPath))
|
|
46
47
|
, m_dic(nullptr)
|
|
47
48
|
, m_dicCrypt(nullptr)
|
|
48
49
|
, m_expectedCapacity(std::max<size_t>(DEFAULT_MMAP_SIZE, roundUp<size_t>(expectedCapacity, DEFAULT_MMAP_SIZE)))
|
|
49
|
-
, m_file(new MemoryFile(m_path, size, (mode & MMKV_ASHMEM) ? MMFILE_TYPE_ASHMEM : MMFILE_TYPE_FILE, m_expectedCapacity))
|
|
50
|
-
, m_metaFile(new MemoryFile(m_crcPath, DEFAULT_MMAP_SIZE, m_file->m_fileType))
|
|
50
|
+
, m_file(new MemoryFile(m_path, size, (mode & MMKV_ASHMEM) ? MMFILE_TYPE_ASHMEM : MMFILE_TYPE_FILE, m_expectedCapacity, isReadOnly()))
|
|
51
|
+
, m_metaFile(new MemoryFile(m_crcPath, DEFAULT_MMAP_SIZE, m_file->m_fileType, 0, isReadOnly()))
|
|
51
52
|
, m_metaInfo(new MMKVMetaInfo())
|
|
52
53
|
, m_crypter(nullptr)
|
|
53
54
|
, m_lock(new ThreadLock())
|
|
54
55
|
, m_fileLock(new FileLock(m_metaFile->getFd(), (mode & MMKV_ASHMEM)))
|
|
55
56
|
, m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
|
|
56
|
-
, m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
|
|
57
|
-
, m_isInterProcess((mode & MMKV_MULTI_PROCESS) != 0 || (mode & CONTEXT_MODE_MULTI_PROCESS) != 0) {
|
|
57
|
+
, m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType)) {
|
|
58
58
|
m_actualSize = 0;
|
|
59
59
|
m_output = nullptr;
|
|
60
60
|
|
|
@@ -78,8 +78,8 @@ MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, stri
|
|
|
78
78
|
|
|
79
79
|
m_crcDigest = 0;
|
|
80
80
|
|
|
81
|
-
m_sharedProcessLock->m_enable =
|
|
82
|
-
m_exclusiveProcessLock->m_enable =
|
|
81
|
+
m_sharedProcessLock->m_enable = isMultiProcess();
|
|
82
|
+
m_exclusiveProcessLock->m_enable = isMultiProcess();
|
|
83
83
|
|
|
84
84
|
// sensitive zone
|
|
85
85
|
/*{
|
|
@@ -90,6 +90,7 @@ MMKV::MMKV(const string &mmapID, int size, MMKVMode mode, string *cryptKey, stri
|
|
|
90
90
|
|
|
91
91
|
MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKey)
|
|
92
92
|
: m_mmapID(mmapID)
|
|
93
|
+
, m_mode(MMKV_ASHMEM)
|
|
93
94
|
, m_path(mappedKVPathWithID(m_mmapID, MMKV_ASHMEM, nullptr))
|
|
94
95
|
, m_crcPath(crcPathWithID(m_mmapID, MMKV_ASHMEM, nullptr))
|
|
95
96
|
, m_dic(nullptr)
|
|
@@ -101,8 +102,7 @@ MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKe
|
|
|
101
102
|
, m_lock(new ThreadLock())
|
|
102
103
|
, m_fileLock(new FileLock(m_metaFile->getFd(), true))
|
|
103
104
|
, m_sharedProcessLock(new InterProcessLock(m_fileLock, SharedLockType))
|
|
104
|
-
, m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType))
|
|
105
|
-
, m_isInterProcess(true) {
|
|
105
|
+
, m_exclusiveProcessLock(new InterProcessLock(m_fileLock, ExclusiveLockType)) {
|
|
106
106
|
|
|
107
107
|
m_actualSize = 0;
|
|
108
108
|
m_output = nullptr;
|
|
@@ -127,8 +127,8 @@ MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKe
|
|
|
127
127
|
|
|
128
128
|
m_crcDigest = 0;
|
|
129
129
|
|
|
130
|
-
m_sharedProcessLock->m_enable =
|
|
131
|
-
m_exclusiveProcessLock->m_enable =
|
|
130
|
+
m_sharedProcessLock->m_enable = true;
|
|
131
|
+
m_exclusiveProcessLock->m_enable = true;
|
|
132
132
|
|
|
133
133
|
// sensitive zone
|
|
134
134
|
/*{
|
|
@@ -138,7 +138,7 @@ MMKV::MMKV(const string &mmapID, int ashmemFD, int ashmemMetaFD, string *cryptKe
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, string *cryptKey, string *rootPath, size_t expectedCapacity) {
|
|
141
|
-
if (mmapID.empty()) {
|
|
141
|
+
if (mmapID.empty() || !g_instanceLock) {
|
|
142
142
|
return nullptr;
|
|
143
143
|
}
|
|
144
144
|
SCOPED_LOCK(g_instanceLock);
|
|
@@ -164,7 +164,7 @@ MMKV *MMKV::mmkvWithID(const string &mmapID, int size, MMKVMode mode, string *cr
|
|
|
164
164
|
|
|
165
165
|
MMKV *MMKV::mmkvWithAshmemFD(const string &mmapID, int fd, int metaFD, string *cryptKey) {
|
|
166
166
|
|
|
167
|
-
if (fd < 0) {
|
|
167
|
+
if (fd < 0 || !g_instanceLock) {
|
|
168
168
|
return nullptr;
|
|
169
169
|
}
|
|
170
170
|
SCOPED_LOCK(g_instanceLock);
|
|
@@ -213,7 +213,7 @@ bool MMKV::checkProcessMode() {
|
|
|
213
213
|
return true;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
if (
|
|
216
|
+
if (isMultiProcess()) {
|
|
217
217
|
if (!m_exclusiveProcessModeLock) {
|
|
218
218
|
m_exclusiveProcessModeLock = new InterProcessLock(m_fileModeLock, ExclusiveLockType);
|
|
219
219
|
}
|
package/MMKV/Core/MMKV_IO.cpp
CHANGED
|
@@ -81,7 +81,7 @@ void MMKV::loadFromFile() {
|
|
|
81
81
|
checkDataValid(loadFromFile, needFullWriteback);
|
|
82
82
|
MMKVInfo("loading [%s] with %zu actual size, file size %zu, InterProcess %d, meta info "
|
|
83
83
|
"version:%u",
|
|
84
|
-
m_mmapID.c_str(), m_actualSize, m_file->getFileSize(),
|
|
84
|
+
m_mmapID.c_str(), m_actualSize, m_file->getFileSize(), isMultiProcess(), m_metaInfo->m_version);
|
|
85
85
|
auto ptr = (uint8_t *) m_file->getMemory();
|
|
86
86
|
// loading
|
|
87
87
|
if (loadFromFile && m_actualSize > 0) {
|
|
@@ -131,6 +131,10 @@ void MMKV::loadFromFile() {
|
|
|
131
131
|
}
|
|
132
132
|
auto count = m_crypter ? m_dicCrypt->size() : m_dic->size();
|
|
133
133
|
MMKVInfo("loaded [%s] with %zu key-values", m_mmapID.c_str(), count);
|
|
134
|
+
// auto keys = allKeys();
|
|
135
|
+
// for (size_t index = 0; index < count; index++) {
|
|
136
|
+
// MMKVInfo("key[%llu]: %s", index, keys[index].c_str());
|
|
137
|
+
// }
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
m_needLoadFromFile = false;
|
|
@@ -303,7 +307,7 @@ void MMKV::checkLoadData() {
|
|
|
303
307
|
loadFromFile();
|
|
304
308
|
return;
|
|
305
309
|
}
|
|
306
|
-
if (!
|
|
310
|
+
if (!isMultiProcess()) {
|
|
307
311
|
return;
|
|
308
312
|
}
|
|
309
313
|
|
|
@@ -397,6 +401,10 @@ bool MMKV::ensureMemorySize(size_t newSize) {
|
|
|
397
401
|
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
398
402
|
return false;
|
|
399
403
|
}
|
|
404
|
+
if (isReadOnly()) {
|
|
405
|
+
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
400
408
|
|
|
401
409
|
if (newSize >= m_output->spaceLeft() || (m_crypter ? m_dicCrypt->empty() : m_dic->empty())) {
|
|
402
410
|
// remove expired keys
|
|
@@ -590,7 +598,7 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
|
|
|
590
598
|
}
|
|
591
599
|
auto itr = m_dicCrypt->find(key);
|
|
592
600
|
if (itr != m_dicCrypt->end()) {
|
|
593
|
-
bool onlyOneKey = !
|
|
601
|
+
bool onlyOneKey = !isMultiProcess() && m_dicCrypt->size() == 1;
|
|
594
602
|
# ifdef MMKV_APPLE
|
|
595
603
|
KVHolderRet_t ret;
|
|
596
604
|
if (onlyOneKey) {
|
|
@@ -629,7 +637,7 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
|
|
|
629
637
|
}
|
|
630
638
|
}
|
|
631
639
|
} else {
|
|
632
|
-
bool needOverride = !
|
|
640
|
+
bool needOverride = !isMultiProcess() && m_dicCrypt->empty() && m_actualSize > 0;
|
|
633
641
|
KVHolderRet_t ret;
|
|
634
642
|
if (needOverride) {
|
|
635
643
|
ret = overrideDataWithKey(data, key, isDataHolder);
|
|
@@ -681,7 +689,7 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
|
|
|
681
689
|
}
|
|
682
690
|
}
|
|
683
691
|
|
|
684
|
-
bool onlyOneKey = !
|
|
692
|
+
bool onlyOneKey = !isMultiProcess() && m_dic->size() == 1;
|
|
685
693
|
if (mmkv_likely(!m_enableKeyExpire)) {
|
|
686
694
|
KVHolderRet_t ret;
|
|
687
695
|
if (onlyOneKey) {
|
|
@@ -713,7 +721,7 @@ bool MMKV::setDataForKey(MMBuffer &&data, MMKVKey_t key, bool isDataHolder) {
|
|
|
713
721
|
}
|
|
714
722
|
}
|
|
715
723
|
} else {
|
|
716
|
-
bool needOverride = !
|
|
724
|
+
bool needOverride = !isMultiProcess() && m_dic->empty() && m_actualSize > 0;
|
|
717
725
|
KVHolderRet_t ret;
|
|
718
726
|
if (needOverride) {
|
|
719
727
|
ret = overrideDataWithKey(data, key, isDataHolder);
|
|
@@ -1338,6 +1346,10 @@ bool MMKV::reKey(const string &cryptKey) {
|
|
|
1338
1346
|
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
1339
1347
|
return false;
|
|
1340
1348
|
}
|
|
1349
|
+
if (isReadOnly()) {
|
|
1350
|
+
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1351
|
+
return false;
|
|
1352
|
+
}
|
|
1341
1353
|
|
|
1342
1354
|
bool ret = false;
|
|
1343
1355
|
if (m_crypter) {
|
|
@@ -1408,6 +1420,10 @@ void MMKV::trim() {
|
|
|
1408
1420
|
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
1409
1421
|
return;
|
|
1410
1422
|
}
|
|
1423
|
+
if (isReadOnly()) {
|
|
1424
|
+
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1411
1427
|
|
|
1412
1428
|
if (m_actualSize == 0) {
|
|
1413
1429
|
clearAll();
|
|
@@ -1452,6 +1468,10 @@ void MMKV::clearAll(bool keepSpace) {
|
|
|
1452
1468
|
MMKVWarning("[%s] file not valid", m_mmapID.c_str());
|
|
1453
1469
|
return;
|
|
1454
1470
|
}
|
|
1471
|
+
if (isReadOnly()) {
|
|
1472
|
+
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1473
|
+
return;
|
|
1474
|
+
}
|
|
1455
1475
|
|
|
1456
1476
|
if (m_file->getFileSize() == m_expectedCapacity && m_actualSize == 0) {
|
|
1457
1477
|
MMKVInfo("nothing to clear for [%s]", m_mmapID.c_str());
|
|
@@ -1524,6 +1544,9 @@ bool MMKV::isFileValid(const string &mmapID, MMKVPath_t *relatePath) {
|
|
|
1524
1544
|
}
|
|
1525
1545
|
|
|
1526
1546
|
bool MMKV::removeStorage(const std::string &mmapID, MMKVPath_t *relatePath) {
|
|
1547
|
+
if (!g_instanceLock) {
|
|
1548
|
+
return false;
|
|
1549
|
+
}
|
|
1527
1550
|
auto mmapKey = mmapedKVKey(mmapID, relatePath);
|
|
1528
1551
|
#ifdef MMKV_ANDROID
|
|
1529
1552
|
auto &realID = mmapKey; // historically Android mistakenly use mmapKey as mmapID
|
|
@@ -1625,6 +1648,10 @@ bool MMKV::enableAutoKeyExpire(uint32_t expiredInSeconds) {
|
|
|
1625
1648
|
if (m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
|
|
1626
1649
|
return true;
|
|
1627
1650
|
}
|
|
1651
|
+
if (isReadOnly()) {
|
|
1652
|
+
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1653
|
+
return false;
|
|
1654
|
+
}
|
|
1628
1655
|
|
|
1629
1656
|
auto autoRecordExpireTime = (m_expiredInSeconds != 0);
|
|
1630
1657
|
auto time = autoRecordExpireTime ? getCurrentTimeInSecond() + m_expiredInSeconds : 0;
|
|
@@ -1685,6 +1712,10 @@ bool MMKV::disableAutoKeyExpire() {
|
|
|
1685
1712
|
if (!m_metaInfo->hasFlag(MMKVMetaInfo::EnableKeyExipre)) {
|
|
1686
1713
|
return true;
|
|
1687
1714
|
}
|
|
1715
|
+
if (isReadOnly()) {
|
|
1716
|
+
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
1717
|
+
return false;
|
|
1718
|
+
}
|
|
1688
1719
|
|
|
1689
1720
|
MMKVInfo("erase previous recorded expire date for all keys inside [%s]", m_mmapID.c_str());
|
|
1690
1721
|
m_metaInfo->unsetFlag(MMKVMetaInfo::EnableKeyExipre);
|
package/MMKV/Core/MMKV_OSX.cpp
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
# endif
|
|
43
43
|
|
|
44
44
|
# ifdef __aarch64__
|
|
45
|
-
# include "Checksum.h"
|
|
45
|
+
# include "crc32/Checksum.h"
|
|
46
46
|
# endif
|
|
47
47
|
|
|
48
48
|
# if __has_feature(objc_arc)
|
|
@@ -94,6 +94,9 @@ bool MLockPtr::isMLockPtrEnabled = true;
|
|
|
94
94
|
static bool g_isInBackground = false;
|
|
95
95
|
|
|
96
96
|
void MMKV::setIsInBackground(bool isInBackground) {
|
|
97
|
+
if (!g_instanceLock) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
97
100
|
SCOPED_LOCK(g_instanceLock);
|
|
98
101
|
|
|
99
102
|
g_isInBackground = isInBackground;
|
|
@@ -101,6 +104,9 @@ void MMKV::setIsInBackground(bool isInBackground) {
|
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
bool MMKV::isInBackground() {
|
|
107
|
+
if (!g_instanceLock) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
104
110
|
SCOPED_LOCK(g_instanceLock);
|
|
105
111
|
|
|
106
112
|
return g_isInBackground;
|
|
@@ -300,9 +306,13 @@ NSArray *MMKV::allKeys(bool filterExpire) {
|
|
|
300
306
|
return keys;
|
|
301
307
|
}
|
|
302
308
|
|
|
303
|
-
|
|
309
|
+
bool MMKV::removeValuesForKeys(NSArray *arrKeys) {
|
|
310
|
+
if (isReadOnly()) {
|
|
311
|
+
MMKVWarning("[%s] file readonly", m_mmapID.c_str());
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
304
314
|
if (arrKeys.count == 0) {
|
|
305
|
-
return;
|
|
315
|
+
return true;
|
|
306
316
|
}
|
|
307
317
|
if (arrKeys.count == 1) {
|
|
308
318
|
return removeValueForKey(arrKeys[0]);
|
|
@@ -337,8 +347,9 @@ void MMKV::removeValuesForKeys(NSArray *arrKeys) {
|
|
|
337
347
|
if (deleteCount > 0) {
|
|
338
348
|
m_hasFullWriteback = false;
|
|
339
349
|
|
|
340
|
-
fullWriteback();
|
|
350
|
+
return fullWriteback();
|
|
341
351
|
}
|
|
352
|
+
return true;
|
|
342
353
|
}
|
|
343
354
|
|
|
344
355
|
void MMKV::enumerateKeys(EnumerateBlock block) {
|
package/MMKV/Core/MemoryFile.cpp
CHANGED
|
@@ -50,7 +50,10 @@ File::File(MMKVPath_t path, OpenFlag flag) : m_path(std::move(path)), m_fd(-1),
|
|
|
50
50
|
open();
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
MemoryFile::MemoryFile(MMKVPath_t path, size_t expectedCapacity
|
|
53
|
+
MemoryFile::MemoryFile(MMKVPath_t path, size_t expectedCapacity, bool readOnly)
|
|
54
|
+
: m_diskFile(std::move(path), readOnly ? OpenFlag::ReadOnly : (OpenFlag::ReadWrite | OpenFlag::Create))
|
|
55
|
+
, m_ptr(nullptr), m_size(0), m_readOnly(readOnly)
|
|
56
|
+
{
|
|
54
57
|
reloadFromFile(expectedCapacity);
|
|
55
58
|
}
|
|
56
59
|
# endif // !defined(MMKV_ANDROID)
|
|
@@ -61,7 +64,7 @@ void tryResetFileProtection(const string &path);
|
|
|
61
64
|
|
|
62
65
|
static int OpenFlag2NativeFlag(OpenFlag flag) {
|
|
63
66
|
int native = O_CLOEXEC;
|
|
64
|
-
if (flag & OpenFlag::ReadWrite) {
|
|
67
|
+
if ((flag & OpenFlagRWMask) == OpenFlag::ReadWrite) {
|
|
65
68
|
native |= O_RDWR;
|
|
66
69
|
} else if (flag & OpenFlag::ReadOnly) {
|
|
67
70
|
native |= O_RDONLY;
|
|
@@ -92,10 +95,10 @@ bool File::open() {
|
|
|
92
95
|
}
|
|
93
96
|
m_fd = ::open(m_path.c_str(), OpenFlag2NativeFlag(m_flag), S_IRWXU);
|
|
94
97
|
if (!isFileValid()) {
|
|
95
|
-
MMKVError("fail to open [%s], %d(%s)", m_path.c_str(), errno, strerror(errno));
|
|
98
|
+
MMKVError("fail to open [%s], flag %x, %d(%s)", m_path.c_str(), m_flag, errno, strerror(errno));
|
|
96
99
|
return false;
|
|
97
100
|
}
|
|
98
|
-
MMKVInfo("open fd[%p], %s", m_fd, m_path.c_str());
|
|
101
|
+
MMKVInfo("open fd[%p], flag %x, %s", m_fd, m_flag, m_path.c_str());
|
|
99
102
|
return true;
|
|
100
103
|
}
|
|
101
104
|
|
|
@@ -128,6 +131,10 @@ bool MemoryFile::truncate(size_t size) {
|
|
|
128
131
|
if (size == m_size) {
|
|
129
132
|
return true;
|
|
130
133
|
}
|
|
134
|
+
if (m_readOnly) {
|
|
135
|
+
// truncate readonly file not allow
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
131
138
|
# ifdef MMKV_ANDROID
|
|
132
139
|
if (m_diskFile.m_fileType == MMFILE_TYPE_ASHMEM) {
|
|
133
140
|
if (size > m_size) {
|
|
@@ -182,6 +189,10 @@ bool MemoryFile::truncate(size_t size) {
|
|
|
182
189
|
}
|
|
183
190
|
|
|
184
191
|
bool MemoryFile::msync(SyncFlag syncFlag) {
|
|
192
|
+
if (m_readOnly) {
|
|
193
|
+
// there's no point in msync() readonly memory
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
185
196
|
if (m_ptr) {
|
|
186
197
|
auto ret = ::msync(m_ptr, m_size, syncFlag ? MS_SYNC : MS_ASYNC);
|
|
187
198
|
if (ret == 0) {
|
|
@@ -194,9 +205,10 @@ bool MemoryFile::msync(SyncFlag syncFlag) {
|
|
|
194
205
|
|
|
195
206
|
bool MemoryFile::mmap() {
|
|
196
207
|
auto oldPtr = m_ptr;
|
|
197
|
-
|
|
208
|
+
auto mode = m_readOnly ? PROT_READ : (PROT_READ | PROT_WRITE);
|
|
209
|
+
m_ptr = (char *) ::mmap(m_ptr, m_size, mode, MAP_SHARED, m_diskFile.m_fd, 0);
|
|
198
210
|
if (m_ptr == MAP_FAILED) {
|
|
199
|
-
MMKVError("fail to mmap [%s], %s", m_diskFile.m_path.c_str(), strerror(errno));
|
|
211
|
+
MMKVError("fail to mmap [%s], mode %x, %s", m_diskFile.m_path.c_str(), mode, strerror(errno));
|
|
200
212
|
m_ptr = nullptr;
|
|
201
213
|
return false;
|
|
202
214
|
}
|
|
@@ -226,7 +238,7 @@ void MemoryFile::reloadFromFile(size_t expectedCapacity) {
|
|
|
226
238
|
mmkv::getFileSize(m_diskFile.m_fd, m_size);
|
|
227
239
|
size_t expectedSize = std::max<size_t>(DEFAULT_MMAP_SIZE, roundUp<size_t>(expectedCapacity, DEFAULT_MMAP_SIZE));
|
|
228
240
|
// round up to (n * pagesize)
|
|
229
|
-
if (m_size < expectedSize || (m_size % DEFAULT_MMAP_SIZE != 0)) {
|
|
241
|
+
if (!m_readOnly && (m_size < expectedSize || (m_size % DEFAULT_MMAP_SIZE != 0))) {
|
|
230
242
|
InterProcessLock exclusiveLock(&fileLock, ExclusiveLockType);
|
|
231
243
|
SCOPED_LOCK(&exclusiveLock);
|
|
232
244
|
|
|
@@ -240,7 +252,9 @@ void MemoryFile::reloadFromFile(size_t expectedCapacity) {
|
|
|
240
252
|
}
|
|
241
253
|
}
|
|
242
254
|
# ifdef MMKV_IOS
|
|
243
|
-
|
|
255
|
+
if (!m_readOnly) {
|
|
256
|
+
tryResetFileProtection(m_diskFile.m_path);
|
|
257
|
+
}
|
|
244
258
|
# endif
|
|
245
259
|
}
|
|
246
260
|
}
|
|
@@ -556,7 +570,7 @@ void walkInDir(const MMKVPath_t &dirPath, WalkType type, const function<void(con
|
|
|
556
570
|
|
|
557
571
|
while (auto child = readdir(dir)) {
|
|
558
572
|
if ((child->d_type & DT_REG) && (type & WalkFile)) {
|
|
559
|
-
#
|
|
573
|
+
#if defined(_DIRENT_HAVE_D_NAMLEN) || defined(__APPLE__)
|
|
560
574
|
stpcpy(childPath + folderPathLength, child->d_name);
|
|
561
575
|
childPath[folderPathLength + child->d_namlen] = 0;
|
|
562
576
|
#else
|
|
@@ -564,7 +578,7 @@ void walkInDir(const MMKVPath_t &dirPath, WalkType type, const function<void(con
|
|
|
564
578
|
#endif
|
|
565
579
|
walker(childPath, WalkFile);
|
|
566
580
|
} else if ((child->d_type & DT_DIR) && (type & WalkFolder)) {
|
|
567
|
-
#
|
|
581
|
+
#if defined(_DIRENT_HAVE_D_NAMLEN) || defined(__APPLE__)
|
|
568
582
|
if ((child->d_namlen == 1 && child->d_name[0] == '.') ||
|
|
569
583
|
(child->d_namlen == 2 && child->d_name[0] == '.' && child->d_name[1] == '.')) {
|
|
570
584
|
continue;
|