• 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_local.h"
16 
17 #include <cerrno>
18 #include <dirent.h>
19 
20 #include "cloud_file_fault_event.h"
21 #include "file_operations_cloud.h"
22 #include "file_operations_helper.h"
23 #include "fuse_ioctl.h"
24 #include "utils_log.h"
25 #include "xcollie_helper.h"
26 
27 namespace OHOS {
28 namespace FileManagement {
29 namespace CloudDisk {
30 using namespace std;
31 using namespace CloudFile;
32 static const int32_t BUNDLE_NAME_OFFSET = 1000000000;
33 static const int32_t STAT_MODE_DIR = 0771;
34 static const float LOOKUP_TIMEOUT = 60.0;
35 #ifdef HICOLLIE_ENABLE
36 static const unsigned int LOOKUP_TIMEOUT_S = 1;
37 static const unsigned int GETATTR_TIMEOUT_S = 1;
38 #endif
39 
DoLocalLookup(fuse_req_t req,fuse_ino_t parent,const char * name,struct fuse_entry_param * e)40 static int32_t DoLocalLookup(fuse_req_t req, fuse_ino_t parent, const char *name,
41                              struct fuse_entry_param *e)
42 {
43     bool createFlag = false;
44     struct CloudDiskFuseData *data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
45     string path = FileOperationsHelper::GetCloudDiskLocalPath(data->userId, name);
46     std::unique_lock<std::shared_mutex> cWLock(data->cacheLock, std::defer_lock);
47     string key = std::to_string(parent) + name;
48     int64_t localId = FileOperationsHelper::FindLocalId(data, key);
49     auto child = FileOperationsHelper::FindCloudDiskInode(data, localId);
50     if (child == nullptr) {
51         child = make_shared<CloudDiskInode>();
52         createFlag = true;
53         LOGD("new child %{public}s", name);
54     }
55     std::unique_lock<std::shared_mutex> lWLock(data->localIdLock, std::defer_lock);
56     child->refCount++;
57     if (createFlag) {
58         if (stat(path.c_str(), &child->stat) != 0) {
59             CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{child->bundleName, CloudFile::FaultOperation::LOOKUP,
60                 CloudFile::FaultType::INODE_FILE, errno, "lookup " + GetAnonyString(path) + " error, err: " +
61                 std::to_string(errno)});
62             return errno;
63         }
64         child->stat.st_mode |= STAT_MODE_DIR;
65         child->parent = parent;
66         child->path = path;
67         auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
68         child->layer = FileOperationsHelper::GetNextLayer(parentInode, parent);
69         localId = FileOperationsHelper::GetFixedLayerRootId(child->layer);
70         if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
71             std::lock_guard<std::shared_mutex> bWLock(data->bundleNameIdLock);
72             data->bundleNameId++;
73             localId = data->bundleNameId + BUNDLE_NAME_OFFSET;
74         }
75         child->stat.st_ino = static_cast<uint64_t>(localId);
76         child->ops = make_shared<FileOperationsLocal>();
77         cWLock.lock();
78         data->inodeCache[localId] = child;
79         cWLock.unlock();
80         lWLock.lock();
81         data->localIdCache[key] = localId;
82         lWLock.unlock();
83     }
84     if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
85         child->bundleName = name;
86         child->ops = make_shared<FileOperationsCloud>();
87     }
88     e->ino = static_cast<fuse_ino_t>(localId);
89     FileOperationsHelper::GetInodeAttr(child, &e->attr);
90     return 0;
91 }
92 
Lookup(fuse_req_t req,fuse_ino_t parent,const char * name)93 void FileOperationsLocal::Lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
94 {
95     struct fuse_entry_param e;
96     int32_t err;
97     e.attr_timeout = LOOKUP_TIMEOUT;
98     e.entry_timeout = LOOKUP_TIMEOUT;
99 #ifdef HICOLLIE_ENABLE
100     auto xcollieId = XCollieHelper::SetTimer("CloudDisk_Lookup", LOOKUP_TIMEOUT_S, nullptr, nullptr, false);
101 #endif
102     err = DoLocalLookup(req, parent, name, &e);
103     if (err) {
104         fuse_reply_err(req, err);
105     } else {
106         fuse_reply_entry(req, &e);
107     }
108 #ifdef HICOLLIE_ENABLE
109     XCollieHelper::CancelTimer(xcollieId);
110 #endif
111 }
112 
GetAttr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)113 void FileOperationsLocal::GetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
114 {
115 #ifdef HICOLLIE_ENABLE
116     auto xcollieId = XCollieHelper::SetTimer("CloudDisk_GetAttr", GETATTR_TIMEOUT_S, nullptr, nullptr, false);
117 #endif
118     struct CloudDiskFuseData *data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
119     if (ino == FUSE_ROOT_ID) {
120         string path = FileOperationsHelper::GetCloudDiskRootPath(data->userId);
121 
122         struct stat statBuf;
123         int err = stat(path.c_str(), &statBuf);
124         if (err != 0) {
125             CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETATTR,
126                 CloudFile::FaultType::FILE, errno, "lookup " + GetAnonyString(path) + " error, err: " +
127                 std::to_string(errno)});
128             fuse_reply_err(req, errno);
129 #ifdef HICOLLIE_ENABLE
130             XCollieHelper::CancelTimer(xcollieId);
131 #endif
132             return;
133         }
134         fuse_reply_attr(req, &statBuf, 0);
135 #ifdef HICOLLIE_ENABLE
136         XCollieHelper::CancelTimer(xcollieId);
137 #endif
138         return;
139     }
140     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
141     if (inoPtr == nullptr) {
142         CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETATTR,
143             CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
144         fuse_reply_err(req, EINVAL);
145 #ifdef HICOLLIE_ENABLE
146         XCollieHelper::CancelTimer(xcollieId);
147 #endif
148         return;
149     }
150     fuse_reply_attr(req, &inoPtr->stat, 0);
151 #ifdef HICOLLIE_ENABLE
152     XCollieHelper::CancelTimer(xcollieId);
153 #endif
154 }
155 
ReadDir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)156 void FileOperationsLocal::ReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
157                                   struct fuse_file_info *fi)
158 {
159     (void) fi;
160     string path;
161     struct CloudDiskFuseData *data =
162         reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
163     if (ino == FUSE_ROOT_ID) {
164         path = FileOperationsHelper::GetCloudDiskRootPath(data->userId);
165     } else {
166         auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
167         if (inoPtr == nullptr) {
168             CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READDIR,
169                 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
170             fuse_reply_err(req, EINVAL);
171             return;
172         }
173         path = inoPtr->path;
174     }
175     DIR* dir = opendir(path.c_str());
176     if (dir == NULL) {
177         CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READDIR,
178             CloudFile::FaultType::FILE, errno, "opendir error " + std::to_string(errno) + ", path: " +
179             GetAnonyString(path)});
180         return;
181     }
182 
183     struct dirent *entry;
184     string entryData;
185     size_t len = 0;
186     while ((entry = readdir(dir)) != NULL) {
187         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
188             continue;
189         }
190 
191         string childPath = FileOperationsHelper::GetCloudDiskLocalPath(data->userId,
192             entry->d_name);
193         int64_t key = FileOperationsHelper::FindLocalId(data, std::to_string(ino) +
194             entry->d_name);
195         auto childPtr = FileOperationsHelper::FindCloudDiskInode(data, key);
196         if (childPtr == nullptr) {
197             childPtr = FileOperationsHelper::GenerateCloudDiskInode(data, ino,
198                 entry->d_name, childPath.c_str());
199         }
200         if (childPtr == nullptr) {
201             continue;
202         }
203         FileOperationsHelper::AddDirEntry(req, entryData, len, entry->d_name, childPtr);
204     }
205     FileOperationsHelper::FuseReplyLimited(req, entryData.c_str(), len, off, size);
206     closedir(dir);
207     return;
208 }
209 
CleanCache(fuse_req_t req)210 static void CleanCache(fuse_req_t req)
211 {
212     LOGI("begin clean clouddisk metafile");
213     MetaFileMgr::GetInstance().CloudDiskClearAll();
214     fuse_reply_ioctl(req, 0, NULL, 0);
215 }
216 
Ioctl(fuse_req_t req,fuse_ino_t ino,int cmd,void * arg,struct fuse_file_info * fi,unsigned flags,const void * inBuf,size_t inBufsz,size_t outBufsz)217 void FileOperationsLocal::Ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, struct fuse_file_info *fi,
218                                 unsigned flags, const void *inBuf, size_t inBufsz, size_t outBufsz)
219 {
220     if (static_cast<unsigned int>(cmd) == HMDFS_IOC_CLEAN_CACHE_DAEMON) {
221         CleanCache(req);
222     } else {
223         LOGE("Invalid argument, cmd is not supported");
224         fuse_reply_err(req, EINVAL);
225         return;
226     }
227 }
228 } // namespace CloudDisk
229 } // namespace FileManagement
230 } // namespace OHOS
231