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