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