1 /*
2  * Copyright (c) 2023-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 }
36 
GetCloudDiskRootPath(int32_t userId)37 string FileOperationsHelper::GetCloudDiskRootPath(int32_t userId)
38 {
39     return LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) + LOCAL_PATH_HMDFS_CLOUD;
40 }
41 
GetCloudDiskLocalPath(int32_t userId,string fileName)42 string FileOperationsHelper::GetCloudDiskLocalPath(int32_t userId, string fileName)
43 {
44     if (fileName == "data") {
45         return LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) +
46                LOCAL_PATH_HMDFS_CLOUD_DATA;
47     } else if (fileName == "/") {
48         return GetCloudDiskRootPath(userId);
49     } else {
50         return LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) +
51                LOCAL_PATH_HMDFS_CLOUD_DATA + fileName;
52     }
53 }
54 
GetInodeAttr(shared_ptr<CloudDiskInode> ino,struct stat * statBuf)55 void FileOperationsHelper::GetInodeAttr(shared_ptr<CloudDiskInode> ino, struct stat *statBuf)
56 {
57     statBuf->st_ino = ino->stat.st_ino;
58     statBuf->st_uid = ino->stat.st_uid;
59     statBuf->st_gid = ino->stat.st_gid;
60     statBuf->st_mtime = ino->stat.st_mtime;
61     statBuf->st_ctime = ino->stat.st_ctime;
62     statBuf->st_atime = ino->stat.st_atime;
63     statBuf->st_mode = ino->stat.st_mode;
64     statBuf->st_nlink = ino->stat.st_nlink;
65     if (statBuf->st_mode & S_IFREG) {
66         statBuf->st_size = ino->stat.st_size;
67     }
68 }
69 
GetNextLayer(std::shared_ptr<CloudDiskInode> inoPtr,fuse_ino_t ino)70 int32_t FileOperationsHelper::GetNextLayer(std::shared_ptr<CloudDiskInode> inoPtr, fuse_ino_t ino)
71 {
72     if (ino == FUSE_ROOT_ID) {
73         return CLOUD_DISK_INODE_ZERO_LAYER;
74     }
75     if (inoPtr->layer >= CLOUD_DISK_INODE_OTHER_LAYER) {
76         return CLOUD_DISK_INODE_OTHER_LAYER;
77     } else {
78         return inoPtr->layer + 1;
79     }
80 }
81 
GetFixedLayerRootId(int32_t layer)82 int32_t FileOperationsHelper::GetFixedLayerRootId(int32_t layer)
83 {
84     if (layer == CLOUD_DISK_INODE_ZERO_LAYER) {
85         return CLOUD_DISK_INODE_ZERO_LAYER_LOCALID;
86     } else if (layer == CLOUD_DISK_INODE_FIRST_LAYER) {
87         return CLOUD_DISK_INODE_FIRST_LAYER_LOCALID;
88     }
89     return CLOUD_DISK_INODE_LAYER_LOCALID_UNKNOWN;
90 }
91 
FindCloudDiskInode(struct CloudDiskFuseData * data,int64_t key)92 shared_ptr<CloudDiskInode> FileOperationsHelper::FindCloudDiskInode(struct CloudDiskFuseData *data,
93                                                                     int64_t key)
94 {
95     shared_ptr<CloudDiskInode> ret;
96     shared_lock<shared_mutex> rLock(data->cacheLock, std::defer_lock);
97     rLock.lock();
98     auto it = data->inodeCache.find(key);
99     if (it != data->inodeCache.end()) {
100         ret = it->second;
101     } else {
102         ret = nullptr;
103     }
104     rLock.unlock();
105     return ret;
106 }
107 
FindCloudDiskFile(struct CloudDiskFuseData * data,int64_t key)108 shared_ptr<CloudDiskFile> FileOperationsHelper::FindCloudDiskFile(struct CloudDiskFuseData *data,
109                                                                   int64_t key)
110 {
111     shared_ptr<CloudDiskFile> ret;
112     shared_lock<shared_mutex> rLock(data->fileLock, std::defer_lock);
113     rLock.lock();
114     auto it = data->fileCache.find(key);
115     if (it != data->fileCache.end()) {
116         ret = it->second;
117     } else {
118         ret = nullptr;
119     }
120     rLock.unlock();
121     return ret;
122 }
123 
FindLocalId(struct CloudDiskFuseData * data,const std::string & key)124 int64_t FileOperationsHelper::FindLocalId(struct CloudDiskFuseData *data, const std::string &key)
125 {
126     int64_t ret = -1;
127     shared_lock<shared_mutex> rLock(data->localIdLock, std::defer_lock);
128     rLock.lock();
129     auto it = data->localIdCache.find(key);
130     if (it != data->localIdCache.end()) {
131         ret = it->second;
132     } else {
133         ret = -1;
134     }
135     rLock.unlock();
136     return ret;
137 }
138 
AddDirEntry(fuse_req_t req,std::string & buf,size_t & size,const char * name,std::shared_ptr<CloudDiskInode> ino)139 void FileOperationsHelper::AddDirEntry(fuse_req_t req, std::string &buf, size_t &size, const char *name,
140                                        std::shared_ptr<CloudDiskInode> ino)
141 {
142     size_t oldSize = size;
143     size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
144     buf.resize(size);
145     fuse_add_direntry(req, &buf[oldSize], size - oldSize, name, &ino->stat, size);
146 }
147 
FuseReplyLimited(fuse_req_t req,const char * buf,size_t bufSize,off_t off,size_t maxSize)148 void FileOperationsHelper::FuseReplyLimited(fuse_req_t req, const char *buf, size_t bufSize,
149                                             off_t off, size_t maxSize)
150 {
151     if (off < bufSize) {
152         size_t size = (bufSize - off) < maxSize ? (bufSize - off) : maxSize;
153         fuse_reply_buf(req, buf + off, size);
154     } else {
155         fuse_reply_buf(req, NULL, 0);
156     }
157 }
158 
GenerateCloudDiskInode(struct CloudDiskFuseData * data,fuse_ino_t parent,const string & fileName,const string & path)159 shared_ptr<CloudDiskInode> FileOperationsHelper::GenerateCloudDiskInode(struct CloudDiskFuseData *data,
160                                                                         fuse_ino_t parent,
161                                                                         const string &fileName,
162                                                                         const string &path)
163 {
164     std::unique_lock<std::shared_mutex> cWLock(data->cacheLock, std::defer_lock);
165     std::unique_lock<std::shared_mutex> lWLock(data->localIdLock, std::defer_lock);
166     shared_ptr<CloudDiskInode> child = make_shared<CloudDiskInode>();
167     int32_t err = stat(path.c_str(), &child->stat);
168     if (err != 0) {
169         LOGE("GenerateCloudDiskInode %{public}s error, err: %{public}d", GetAnonyString(path).c_str(), errno);
170         return nullptr;
171     }
172     child->stat.st_mode |= STAT_MODE_DIR;
173     auto parentInode = FindCloudDiskInode(data, parent);
174     if (parentInode == nullptr) {
175         LOGE("parent inode not found");
176         return nullptr;
177     }
178     child->refCount++;
179     child->parent = parent;
180     child->path = path;
181     child->layer = GetNextLayer(parentInode, parent);
182     int64_t localId = GetFixedLayerRootId(child->layer);
183     if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
184         std::lock_guard<std::shared_mutex> bWLock(data->bundleNameIdLock);
185         data->bundleNameId++;
186         localId = data->bundleNameId + BUNDLE_NAME_OFFSET;
187     }
188     child->stat.st_ino = static_cast<uint64_t>(localId);
189     child->ops = make_shared<FileOperationsLocal>();
190     cWLock.lock();
191     data->inodeCache[localId] = child;
192     cWLock.unlock();
193     lWLock.lock();
194     data->localIdCache[path] = localId;
195     lWLock.unlock();
196     if (child->layer == CLOUD_DISK_INODE_FIRST_LAYER) {
197         child->bundleName = fileName;
198         child->ops = make_shared<FileOperationsCloud>();
199     }
200     return child;
201 }
202 
PutCloudDiskInode(struct CloudDiskFuseData * data,shared_ptr<CloudDiskInode> inoPtr,uint64_t num,int64_t key)203 void FileOperationsHelper::PutCloudDiskInode(struct CloudDiskFuseData *data,
204                                              shared_ptr<CloudDiskInode> inoPtr, uint64_t num, int64_t key)
205 {
206     std::unique_lock<std::shared_mutex> wLock(data->cacheLock, std::defer_lock);
207     if (inoPtr == nullptr) {
208         LOGD("Get an invalid inode!");
209         return;
210     }
211     inoPtr->refCount -= num;
212     if (inoPtr->refCount == 0) {
213         LOGD("node released: %{public}" PRId64 "", key);
214         wLock.lock();
215         data->inodeCache.erase(key);
216         wLock.unlock();
217     }
218 }
219 
PutCloudDiskFile(struct CloudDiskFuseData * data,shared_ptr<CloudDiskFile> filePtr,int64_t key)220 void FileOperationsHelper::PutCloudDiskFile(struct CloudDiskFuseData *data,
221                                             shared_ptr<CloudDiskFile> filePtr, int64_t key)
222 {
223     std::unique_lock<std::shared_mutex> wLock(data->fileLock, std::defer_lock);
224     if (filePtr == nullptr) {
225         LOGD("Get an invalid file!");
226         return;
227     }
228     if (filePtr->refCount == 0) {
229         LOGD("file released: %{public}" PRId64 "", key);
230         wLock.lock();
231         data->fileCache.erase(key);
232         wLock.unlock();
233     }
234 }
235 
PutLocalId(struct CloudDiskFuseData * data,std::shared_ptr<CloudDiskInode> inoPtr,uint64_t num,const std::string & key)236 void FileOperationsHelper::PutLocalId(struct CloudDiskFuseData *data,
237                                       std::shared_ptr<CloudDiskInode> inoPtr,
238                                       uint64_t num, const std::string &key)
239 {
240     std::unique_lock<std::shared_mutex> wLock(data->localIdLock, std::defer_lock);
241     if (inoPtr == nullptr) {
242         LOGD("Get an invalid inode!");
243         return;
244     }
245     inoPtr->refCount -= num;
246     if (inoPtr->refCount == 0) {
247         LOGD("node released: %{public}s", key.c_str());
248         wLock.lock();
249         data->localIdCache.erase(key);
250         wLock.unlock();
251     }
252 }
253 } // namespace CloudDisk
254 } // namespace FileManagement
255 } // namespace OHOS
256