-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Copy pathMemoryFile_OSX.cpp
150 lines (125 loc) · 4.98 KB
/
MemoryFile_OSX.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* Tencent is pleased to support the open source community by making
* MMKV available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MemoryFile.h"
#include "MMKVLog.h"
#ifdef MMKV_IOS
using namespace std;
namespace mmkv {
void tryResetFileProtection(const string &path) {
@autoreleasepool {
NSString *nsPath = [NSString stringWithUTF8String:path.c_str()];
NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:nsPath error:nullptr];
NSString *protection = [attr valueForKey:NSFileProtectionKey];
MMKVInfo("protection on [%@] is %@", nsPath, protection);
if ([protection isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication] == NO) {
NSMutableDictionary *newAttr = [NSMutableDictionary dictionaryWithDictionary:attr];
[newAttr setObject:NSFileProtectionCompleteUntilFirstUserAuthentication forKey:NSFileProtectionKey];
NSError *err = nil;
[[NSFileManager defaultManager] setAttributes:newAttr ofItemAtPath:nsPath error:&err];
if (err != nil) {
MMKVError("fail to set attribute %@ on [%@]: %@", NSFileProtectionCompleteUntilFirstUserAuthentication,
nsPath, err);
}
}
}
}
} // namespace mmkv
#endif // MMKV_IOS
#ifdef MMKV_APPLE
#include <copyfile.h>
#include <unistd.h>
namespace mmkv {
bool tryAtomicRename(const char *src, const char *dst) {
if (!src || !dst) {
return false;
}
bool renamed = false;
// try atomic swap first
if (@available(iOS 10.0, watchOS 3.0, macOS 10.12, *)) {
// renameat2() equivalent
if (renamex_np(src, dst, RENAME_SWAP) == 0) {
renamed = true;
if (strcmp(src, dst) != 0) {
::unlink(src);
}
} else if (errno != ENOENT) {
MMKVError("fail to renamex_np %s to %s, %s", src, dst, strerror(errno));
}
}
if (!renamed) {
// try old style rename
if (rename(src, dst) != 0) {
MMKVError("fail to rename %s to %s, %s", src, dst, strerror(errno));
return false;
}
}
return true;
}
bool copyFile(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
// prepare a temp file for atomic rename, avoid data corruption of suddent crash
NSString *uniqueFileName = [NSString stringWithFormat:@"mmkv_%zu", (size_t) NSDate.timeIntervalSinceReferenceDate];
NSString *tmpFile = [NSTemporaryDirectory() stringByAppendingPathComponent:uniqueFileName];
if (copyfile(srcPath.c_str(), tmpFile.UTF8String, nullptr, COPYFILE_UNLINK | COPYFILE_CLONE) != 0) {
MMKVError("fail to copyfile [%s] to [%s], %s", srcPath.c_str(), tmpFile.UTF8String, strerror(errno));
return false;
}
MMKVInfo("copyfile [%s] to [%s]", srcPath.c_str(), tmpFile.UTF8String);
if (tryAtomicRename(tmpFile.UTF8String, dstPath.c_str())) {
MMKVInfo("copyfile [%s] to [%s] finish.", srcPath.c_str(), dstPath.c_str());
return true;
}
MMKVInfo("rename fail, try copy file content instead.");
auto ret = copyFileContent(tmpFile.UTF8String, dstPath);
unlink(tmpFile.UTF8String);
return ret;
}
bool copyFileContent(const MMKVPath_t &srcPath, const MMKVPath_t &dstPath) {
File dstFile(dstPath, OpenFlag::WriteOnly | OpenFlag::Create | OpenFlag::Truncate);
if (!dstFile.isFileValid()) {
return false;
}
if (copyFileContent(srcPath, dstFile.getFd())) {
MMKVInfo("copy content from %s to fd[%s] finish", srcPath.c_str(), dstPath.c_str());
return true;
}
MMKVError("fail to copyfile(): target file %s", dstPath.c_str());
return false;
}
bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD) {
if (dstFD < 0) {
return false;
}
File srcFile(srcPath, OpenFlag::ReadOnly);
if (!srcFile.isFileValid()) {
return false;
}
// sendfile() equivalent
if (::fcopyfile(srcFile.getFd(), dstFD, nullptr, COPYFILE_ALL) == 0) {
MMKVInfo("copy content from %s to fd[%d] finish", srcPath.c_str(), dstFD);
return true;
}
MMKVError("fail to copyfile(): %d(%s), source file %s", errno, strerror(errno), srcPath.c_str());
return false;
}
bool copyFileContent(const MMKVPath_t &srcPath, MMKVFileHandle_t dstFD, bool needTruncate) {
return copyFileContent(srcPath, dstFD);
}
} // namespace mmkv
#endif // MMKV_APPLE