1 /*
2  * Copyright (c) 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 
16 #include "clouddisk_notify_utils.h"
17 #include "clouddisk_rdb_utils.h"
18 #include "file_column.h"
19 #include "cloud_pref_impl.h"
20 #include "dfs_error.h"
21 #include "utils_log.h"
22 
23 namespace OHOS::FileManagement::CloudDisk {
24 const uint32_t MAX_QUERY_TIMES = 1024;
25 const string BUNDLENAME_FLAG = "<BundleName>";
26 const string CLOUDDISK_URI_PREFIX = "file://<BundleName>/data/storage/el2/cloud";
27 const string BACKFLASH = "/";
28 const int32_t CloudDiskNotifyUtils::maxCacheCnt_;
29 list<pair<string, CacheNode>> CloudDiskNotifyUtils::cacheList_;
30 unordered_map<string, list<pair<string, CacheNode>>::iterator> CloudDiskNotifyUtils::cacheMap_;
31 mutex CloudDiskNotifyUtils::cacheMutex_;
32 
isRoot(const fuse_ino_t & ino)33 static bool isRoot(const fuse_ino_t &ino)
34 {
35     return ino == FUSE_ROOT_ID;
36 }
37 
GetUriRecursively(CloudDiskFuseData * data,FindCloudDiskInodeFunc func,shared_ptr<CloudDiskInode> inoPtr,string & uri)38 static int32_t GetUriRecursively(CloudDiskFuseData* data, FindCloudDiskInodeFunc func,
39     shared_ptr<CloudDiskInode> inoPtr, string &uri)
40 {
41     string bundleName = inoPtr->bundleName;
42     string realPrefix = CLOUDDISK_URI_PREFIX;
43     realPrefix.replace(realPrefix.find(BUNDLENAME_FLAG), BUNDLENAME_FLAG.length(), bundleName);
44     uint32_t queryTimes = 0;
45     while (!isRoot(inoPtr->parent)) {
46         inoPtr = func(data, inoPtr->parent);
47         if (!inoPtr || inoPtr->fileName.empty()) {
48             break;
49         }
50         uri = inoPtr->fileName + BACKFLASH + uri;
51         queryTimes++;
52         if (uri.length() > PATH_MAX || queryTimes > MAX_QUERY_TIMES) {
53             return E_INVAL_ARG;
54         }
55     }
56     uri = realPrefix + BACKFLASH + uri;
57     LOGD("GetUriRecursively uri: %{public}s", GetAnonyString(uri).c_str());
58     return E_OK;
59 }
60 
GetNotifyData(CloudDiskFuseData * data,FindCloudDiskInodeFunc func,const fuse_ino_t & ino,NotifyData & notifyData)61 int32_t CloudDiskNotifyUtils::GetNotifyData(CloudDiskFuseData* data, FindCloudDiskInodeFunc func,
62     const fuse_ino_t &ino, NotifyData &notifyData)
63 {
64     if (isRoot(ino)) {
65         return E_INVAL_ARG;
66     }
67     auto inoPtr = func(data, ino);
68     if (inoPtr == nullptr) {
69         LOGE("inode not found");
70         return E_INVAL_ARG;
71     }
72     notifyData.uri = inoPtr->fileName;
73     notifyData.isDir = inoPtr->stat.st_mode & S_IFDIR;
74     return GetUriRecursively(data, func, inoPtr, notifyData.uri);
75 }
76 
GetNotifyData(CloudDiskFuseData * data,FindCloudDiskInodeFunc func,const fuse_ino_t & parent,const string & name,NotifyData & notifyData)77 int32_t CloudDiskNotifyUtils::GetNotifyData(CloudDiskFuseData* data, FindCloudDiskInodeFunc func,
78     const fuse_ino_t &parent, const string &name, NotifyData &notifyData)
79 {
80     auto inoPtr = func(data, parent);
81     if (inoPtr == nullptr) {
82         LOGE("inode not found");
83         return E_INVAL_ARG;
84     }
85     notifyData.uri = name;
86     if (!inoPtr->fileName.empty()) {
87         notifyData.uri = inoPtr->fileName + BACKFLASH + notifyData.uri;
88     }
89     return GetUriRecursively(data, func, inoPtr, notifyData.uri);
90 }
91 
GetNotifyData(CloudDiskFuseData * data,FindCloudDiskInodeFunc func,shared_ptr<CloudDiskInode> inoPtr,NotifyData & notifyData)92 int32_t CloudDiskNotifyUtils::GetNotifyData(CloudDiskFuseData* data, FindCloudDiskInodeFunc func,
93     shared_ptr<CloudDiskInode> inoPtr, NotifyData &notifyData)
94 {
95     if (inoPtr == nullptr) {
96         LOGE("inode not found");
97         return E_INVAL_ARG;
98     }
99     notifyData.uri = inoPtr->fileName;
100     notifyData.isDir = inoPtr->stat.st_mode & S_IFDIR;
101     return GetUriRecursively(data, func, inoPtr, notifyData.uri);
102 }
103 
GetNotifyData(CloudDiskFuseData * data,FindCloudDiskInodeFunc func,shared_ptr<CloudDiskInode> pInoPtr,const string & name,NotifyData & notifyData)104 int32_t CloudDiskNotifyUtils::GetNotifyData(CloudDiskFuseData* data, FindCloudDiskInodeFunc func,
105     shared_ptr<CloudDiskInode> pInoPtr, const string &name, NotifyData &notifyData)
106 {
107     if (pInoPtr == nullptr) {
108         LOGE("inode not found");
109         return E_INVAL_ARG;
110     }
111     notifyData.uri = name;
112     if (!pInoPtr->fileName.empty()) {
113         notifyData.uri = pInoPtr->fileName + BACKFLASH + notifyData.uri;
114     }
115     return GetUriRecursively(data, func, pInoPtr, notifyData.uri);
116 }
117 
GetCacheNode(const string & cloudId,CacheNode & cacheNode)118 int32_t CloudDiskNotifyUtils::GetCacheNode(const string &cloudId, CacheNode &cacheNode)
119 {
120     lock_guard<mutex> lock(cacheMutex_);
121     auto it = cacheMap_.find(cloudId);
122     if (it == cacheMap_.end()) {
123         LOGI("Not fount in cache, id: %{public}s", cloudId.c_str());
124         return E_INVAL_ARG;
125     }
126     cacheList_.splice(cacheList_.begin(), cacheList_, it->second);
127     cacheNode = it->second->second;
128     return E_OK;
129 }
130 
PutCacheNode(const string & cloudId,const CacheNode & cacheNode)131 void CloudDiskNotifyUtils::PutCacheNode(const string &cloudId, const CacheNode &cacheNode)
132 {
133     if (cacheNode.isDir != TYPE_DIR_STR) {
134         return;
135     }
136     lock_guard<mutex> lock(cacheMutex_);
137     auto it = cacheMap_.find(cloudId);
138     if (it != cacheMap_.end()) {
139         LOGD("update cache name: %{public}s", GetAnonyString(cacheNode.fileName).c_str());
140         it->second->second = cacheNode;
141         cacheList_.splice(cacheList_.begin(), cacheList_, it->second);
142         return;
143     }
144     if (cacheMap_.size() == maxCacheCnt_) {
145         LOGI("upto max, delete last one");
146         string deleteCloudId = cacheList_.back().first;
147         cacheList_.pop_back();
148         cacheMap_.erase(deleteCloudId);
149     }
150     LOGD("insert to cache name: %{public}s", GetAnonyString(cacheNode.fileName).c_str());
151     cacheList_.emplace_front(cloudId, cacheNode);
152     cacheMap_[cloudId] = cacheList_.begin();
153 }
154 
GetUriFromCache(const string & bundleName,const string & rootId,const CacheNode & cacheNode,string & uri)155 int32_t CloudDiskNotifyUtils::GetUriFromCache(const string &bundleName,
156                                               const string &rootId,
157                                               const CacheNode &cacheNode,
158                                               string &uri)
159 {
160     CacheNode tmpCacheNode;
161     PutCacheNode(cacheNode.cloudId, cacheNode);
162     uri = cacheNode.fileName;
163     tmpCacheNode = cacheNode;
164     int32_t ret;
165     while (tmpCacheNode.parentCloudId != rootId) {
166         ret = GetCacheNode(tmpCacheNode.parentCloudId, tmpCacheNode);
167         if (ret != E_OK) {
168             return ret;
169         }
170         uri = tmpCacheNode.fileName + BACKFLASH + uri;
171     }
172     string realPrefix = CLOUDDISK_URI_PREFIX;
173     realPrefix.replace(realPrefix.find(BUNDLENAME_FLAG), BUNDLENAME_FLAG.length(), bundleName);
174     uri = realPrefix + BACKFLASH + uri;
175     return E_OK;
176 }
177 } // namespace OHOS::FileManagement::CloudDisk