1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "file_operations_helper.h"
16
17 #include <cinttypes>
18 #include <unistd.h>
19
20 #include "file_operations_cloud.h"
21 #include "file_operations_local.h"
22 #include "securec.h"
23 #include "utils_log.h"
24
25 namespace OHOS {
26 namespace FileManagement {
27 namespace CloudDisk {
28 using namespace std;
29 namespace {
30 static const string LOCAL_PATH_DATA_SERVICE_EL2 = "/data/service/el2/";
31 static const string LOCAL_PATH_HMDFS_CLOUD_DATA = "/hmdfs/cloud/data/";
32 static const string LOCAL_PATH_HMDFS_CLOUD = "/hmdfs/cloud/";
33 static const int32_t BUNDLE_NAME_OFFSET = 1000000000;
34 static const int32_t STAT_MODE_DIR = 0771;
35 static const int32_t NULL_PTR = -1;
36 static const int32_t MOCK0 = 0;
37 static const int32_t MOCK1 = 1;
38 static const int32_t MOCK2 = 2;
39 static const int32_t MOCK3 = 3;
40 static const int32_t MOCK4 = 4;
41 }
42
GetCloudDiskRootPath(int32_t userId)43 string FileOperationsHelper::GetCloudDiskRootPath(int32_t userId)
44 {
45 return LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) + LOCAL_PATH_HMDFS_CLOUD;
46 }
47
GetCloudDiskLocalPath(int32_t userId,string fileName)48 string FileOperationsHelper::GetCloudDiskLocalPath(int32_t userId, string fileName)
49 {
50 if (fileName == "data") {
51 return LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) +
52 LOCAL_PATH_HMDFS_CLOUD_DATA;
53 } else if (fileName == "/") {
54 return GetCloudDiskRootPath(userId);
55 } else {
56 return LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) +
57 LOCAL_PATH_HMDFS_CLOUD_DATA + fileName;
58 }
59 }
60
GetInodeAttr(shared_ptr<CloudDiskInode> ino,struct stat * statBuf)61 void FileOperationsHelper::GetInodeAttr(shared_ptr<CloudDiskInode> ino, struct stat *statBuf)
62 {
63 statBuf->st_ino = ino->stat.st_ino;
64 statBuf->st_uid = ino->stat.st_uid;
65 statBuf->st_gid = ino->stat.st_gid;
66 statBuf->st_mtime = ino->stat.st_mtime;
67 statBuf->st_ctime = ino->stat.st_ctime;
68 statBuf->st_atime = ino->stat.st_atime;
69 statBuf->st_mode = ino->stat.st_mode;
70 statBuf->st_nlink = ino->stat.st_nlink;
71 if (statBuf->st_mode & S_IFREG) {
72 statBuf->st_size = ino->stat.st_size;
73 }
74 }
75
GetNextLayer(std::shared_ptr<CloudDiskInode> inoPtr,fuse_ino_t ino)76 int32_t FileOperationsHelper::GetNextLayer(std::shared_ptr<CloudDiskInode> inoPtr, fuse_ino_t ino)
77 {
78 if (ino == FUSE_ROOT_ID) {
79 return CLOUD_DISK_INODE_ZERO_LAYER;
80 }
81 if (inoPtr->layer >= CLOUD_DISK_INODE_OTHER_LAYER) {
82 return CLOUD_DISK_INODE_OTHER_LAYER;
83 } else {
84 return inoPtr->layer + 1;
85 }
86 }
87
GetFixedLayerRootId(int32_t layer)88 int32_t FileOperationsHelper::GetFixedLayerRootId(int32_t layer)
89 {
90 if (layer == CLOUD_DISK_INODE_ZERO_LAYER) {
91 return CLOUD_DISK_INODE_ZERO_LAYER_LOCALID;
92 } else if (layer == CLOUD_DISK_INODE_FIRST_LAYER) {
93 return CLOUD_DISK_INODE_FIRST_LAYER_LOCALID;
94 }
95 return CLOUD_DISK_INODE_LAYER_LOCALID_UNKNOWN;
96 }
97
FindCloudDiskInode(struct CloudDiskFuseData * data,int64_t key)98 shared_ptr<CloudDiskInode> FileOperationsHelper::FindCloudDiskInode(struct CloudDiskFuseData *data,
99 int64_t key)
100 {
101 shared_ptr<CloudDiskInode> ptr = make_shared<CloudDiskInode>();
102 if (key == NULL_PTR) {
103 ptr = nullptr;
104 } else if (key == MOCK0) {
105 ptr->parent = -1;
106 } else if (key == MOCK1) {
107 ptr->parent = 0;
108 } else if (key == MOCK2) {
109 ptr->parent = 0;
110 ptr->bundleName = "com.ohos.photos";
111 ptr->cloudId = "mock";
112 ptr->fileName = "mock";
113 } else if (key == MOCK3) {
114 ptr->parent = 0;
115 ptr->cloudId = "mock";
116 ptr->fileName = "test";
117 } else if (key == MOCK4) {
118 ptr->bundleName = "com.ohos.photos";
119 ptr->parent = 0;
120 ptr->cloudId = "";
121 ptr->fileName = "test";
122 }
123 return ptr;
124 }
125
FindCloudDiskFile(struct CloudDiskFuseData * data,int64_t key)126 shared_ptr<CloudDiskFile> FileOperationsHelper::FindCloudDiskFile(struct CloudDiskFuseData *data,
127 int64_t key)
128 {
129 shared_ptr<CloudDiskFile> ptr = make_shared<CloudDiskFile>();
130 ptr -> type = CLOUD_DISK_FILE_TYPE_LOCAL;
131 ptr -> refCount = 1;
132 ptr -> fileDirty = CLOUD_DISK_FILE_CREATE;
133 if (key == NULL_PTR) {
134 ptr = nullptr;
135 } else if (key == MOCK0) {
136 ptr -> fileDirty = CLOUD_DISK_FILE_UNKNOWN;
137 } else if (key == MOCK1) {
138 string recordType = "";
139 string recordId = "";
140 string assetKey = "";
141 string assetPath = "";
142 ptr -> type = CLOUD_DISK_FILE_TYPE_CLOUD;
143 ptr -> readSession =
144 make_shared<CloudFile::CloudAssetReadSession>(recordType, recordId, assetKey, assetPath);
145 } else if (key == MOCK3) {
146 ptr -> refCount = 0;
147 }
148 return ptr;
149 }
150
FindLocalId(struct CloudDiskFuseData * data,const std::string & key)151 int64_t FileOperationsHelper::FindLocalId(struct CloudDiskFuseData *data, const std::string &key)
152 {
153 int64_t ret = -1;
154 shared_lock<shared_mutex> rLock(data->localIdLock, std::defer_lock);
155 rLock.lock();
156 auto it = data->localIdCache.find(key);
157 if (it != data->localIdCache.end()) {
158 ret = it->second;
159 } else {
160 ret = -1;
161 }
162 rLock.unlock();
163 return ret;
164 }
165
AddDirEntry(fuse_req_t req,std::string & buf,size_t & size,const char * name,std::shared_ptr<CloudDiskInode> ino)166 void FileOperationsHelper::AddDirEntry(fuse_req_t req, std::string &buf, size_t &size, const char *name,
167 std::shared_ptr<CloudDiskInode> ino)
168 {
169 size_t oldSize = size;
170 size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
171 buf.resize(size);
172 fuse_add_direntry(req, &buf[oldSize], size - oldSize, name, &ino->stat, size);
173 }
174
FuseReplyLimited(fuse_req_t req,const char * buf,size_t bufSize,off_t off,size_t maxSize)175 void FileOperationsHelper::FuseReplyLimited(fuse_req_t req, const char *buf, size_t bufSize,
176 off_t off, size_t maxSize)
177 {
178 if (off < bufSize) {
179 size_t size = (bufSize - off) < maxSize ? (bufSize - off) : maxSize;
180 fuse_reply_buf(req, buf + off, size);
181 } else {
182 fuse_reply_buf(req, NULL, 0);
183 }
184 }
185
GenerateCloudDiskInode(struct CloudDiskFuseData * data,fuse_ino_t parent,const string & fileName,const string & path)186 shared_ptr<CloudDiskInode> FileOperationsHelper::GenerateCloudDiskInode(struct CloudDiskFuseData *data,
187 fuse_ino_t parent,
188 const string &fileName,
189 const string &path)
190 {
191 std::unique_lock<std::shared_mutex> cWLock(data->cacheLock, std::defer_lock);
192 std::unique_lock<std::shared_mutex> lWLock(data->localIdLock, std::defer_lock);
193 shared_ptr<CloudDiskInode> child = make_shared<CloudDiskInode>();
194 int32_t err = stat(path.c_str(), &child->stat);
195 if (err != 0) {
196 LOGE("GenerateCloudDiskInode %{public}s error, err: %{public}d", path.c_str(), errno);
197 return nullptr;
198 }
199 child->stat.st_mode |= STAT_MODE_DIR;
200 auto parentInode = FindCloudDiskInode(data, parent);
201 if (parentInode == nullptr) {
202 LOGE("parent inode not found");
203 return nullptr;
204 }
205 child->refCount++;
206 child->parent = parent;
207 child->path = path;
208 child->layer = GetNextLayer(parentInode, parent);
209 int64_t localId = GetFixedLayerRootId(child->layer);
210 if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
211 std::lock_guard<std::shared_mutex> bWLock(data->bundleNameIdLock);
212 data->bundleNameId++;
213 localId = data->bundleNameId + BUNDLE_NAME_OFFSET;
214 }
215 child->stat.st_ino = static_cast<uint64_t>(localId);
216 child->ops = make_shared<FileOperationsLocal>();
217 cWLock.lock();
218 data->inodeCache[localId] = child;
219 cWLock.unlock();
220 lWLock.lock();
221 data->localIdCache[path] = localId;
222 lWLock.unlock();
223 if (child->layer == CLOUD_DISK_INODE_FIRST_LAYER) {
224 child->bundleName = fileName;
225 child->ops = make_shared<FileOperationsCloud>();
226 }
227 return child;
228 }
229
PutCloudDiskInode(struct CloudDiskFuseData * data,shared_ptr<CloudDiskInode> inoPtr,uint64_t num,int64_t key)230 void FileOperationsHelper::PutCloudDiskInode(struct CloudDiskFuseData *data,
231 shared_ptr<CloudDiskInode> inoPtr, uint64_t num, int64_t key)
232 {
233 std::unique_lock<std::shared_mutex> wLock(data->cacheLock, std::defer_lock);
234 if (inoPtr == nullptr) {
235 LOGD("Get an invalid inode!");
236 return;
237 }
238 inoPtr->refCount -= num;
239 if (inoPtr->refCount == 0) {
240 LOGD("node released: %{public}" PRId64 "", key);
241 wLock.lock();
242 data->inodeCache.erase(key);
243 wLock.unlock();
244 }
245 }
246
PutCloudDiskFile(struct CloudDiskFuseData * data,shared_ptr<CloudDiskFile> filePtr,int64_t key)247 void FileOperationsHelper::PutCloudDiskFile(struct CloudDiskFuseData *data,
248 shared_ptr<CloudDiskFile> filePtr, int64_t key)
249 {
250 std::unique_lock<std::shared_mutex> wLock(data->fileLock, std::defer_lock);
251 if (filePtr == nullptr) {
252 LOGD("Get an invalid file!");
253 return;
254 }
255 if (filePtr->refCount == 0) {
256 LOGD("file released: %{public}" PRId64 "", key);
257 wLock.lock();
258 data->fileCache.erase(key);
259 wLock.unlock();
260 }
261 }
262
PutLocalId(struct CloudDiskFuseData * data,std::shared_ptr<CloudDiskInode> inoPtr,uint64_t num,const std::string & key)263 void FileOperationsHelper::PutLocalId(struct CloudDiskFuseData *data,
264 std::shared_ptr<CloudDiskInode> inoPtr,
265 uint64_t num, const std::string &key)
266 {
267 std::unique_lock<std::shared_mutex> wLock(data->localIdLock, std::defer_lock);
268 if (inoPtr == nullptr) {
269 LOGD("Get an invalid inode!");
270 return;
271 }
272 inoPtr->refCount -= num;
273 if (inoPtr->refCount == 0) {
274 LOGD("node released: %{public}s", key.c_str());
275 wLock.lock();
276 data->localIdCache.erase(key);
277 wLock.unlock();
278 }
279 }
280 } // namespace CloudDisk
281 } // namespace FileManagement
282 } // namespace OHOS