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