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