• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 #define MLOG_TAG "Thumbnail"
16 
17 #include "thumbnail_file_utils.h"
18 
19 #include <filesystem>
20 #include <ftw.h>
21 #include <unordered_map>
22 
23 #ifdef HAS_WIFI_MANAGER_PART
24 #include "wifi_device.h"
25 #endif
26 
27 #include "dfx_utils.h"
28 #include "medialibrary_errno.h"
29 #include "medialibrary_kvstore_manager.h"
30 #include "medialibrary_tracer.h"
31 #include "media_file_utils.h"
32 #include "media_log.h"
33 #include "thumbnail_const.h"
34 
35 using namespace std;
36 
37 namespace OHOS {
38 namespace Media {
39 
40 const int32_t OPEN_FDS = 64;
41 const int32_t BEGIN_TIMESTAMP_DIR_LEVEL = 1;
42 const std::string BEGIN_TIMESTAMP_DIR_PREFIX = "beginTimeStamp";
43 
44 const std::string LCD_FILE_NAME = "LCD.jpg";
45 const std::string THUMB_FILE_NAME = "THM.jpg";
46 const std::string THUMB_ASTC_FILE_NAME = "THM_ASTC.astc";
47 static const std::unordered_map<ThumbnailType, std::string> THUMB_FILE_NAME_MAP = {
48     { ThumbnailType::LCD, LCD_FILE_NAME },
49     { ThumbnailType::THUMB, THUMB_FILE_NAME },
50     { ThumbnailType::THUMB_ASTC, THUMB_ASTC_FILE_NAME },
51     { ThumbnailType::LCD_EX, LCD_FILE_NAME },
52     { ThumbnailType::THUMB_EX, THUMB_FILE_NAME }
53 };
54 
GetThumbnailSuffix(ThumbnailType type)55 std::string ThumbnailFileUtils::GetThumbnailSuffix(ThumbnailType type)
56 {
57     string suffix;
58     switch (type) {
59         case ThumbnailType::THUMB:
60             suffix = THUMBNAIL_THUMB_SUFFIX;
61             break;
62         case ThumbnailType::THUMB_ASTC:
63             suffix = THUMBNAIL_THUMB_ASTC_SUFFIX;
64             break;
65         case ThumbnailType::LCD:
66             suffix = THUMBNAIL_LCD_SUFFIX;
67             break;
68         default:
69             return "";
70     }
71     return suffix;
72 }
73 
GetThumbnailDir(const ThumbnailData & data)74 std::string ThumbnailFileUtils::GetThumbnailDir(const ThumbnailData &data)
75 {
76     CHECK_AND_RETURN_RET_LOG(!data.path.empty(), "", "Path is empty");
77     string fileName = GetThumbnailPath(data.path, THUMBNAIL_LCD_SUFFIX);
78     return MediaFileUtils::GetParentPath(fileName);
79 }
80 
GetThumbExDir(const ThumbnailData & data)81 std::string ThumbnailFileUtils::GetThumbExDir(const ThumbnailData &data)
82 {
83     CHECK_AND_RETURN_RET_LOG(!data.path.empty(), "", "Path is empty");
84     string fileName = GetThumbnailPath(data.path, THUMBNAIL_THUMB_EX_SUFFIX);
85     return MediaFileUtils::GetParentPath(fileName);
86 }
87 
IsExThumbType(ThumbnailType type)88 bool IsExThumbType(ThumbnailType type)
89 {
90     if (type == ThumbnailType::LCD_EX || type == ThumbnailType::THUMB_EX) {
91         return true;
92     }
93     return false;
94 }
95 
GetThumbFileSize(const ThumbnailData & data,const ThumbnailType type,size_t & size)96 bool ThumbnailFileUtils::GetThumbFileSize(const ThumbnailData& data, const ThumbnailType type, size_t& size)
97 {
98     CHECK_AND_RETURN_RET_LOG(THUMB_FILE_NAME_MAP.find(type) != THUMB_FILE_NAME_MAP.end(), false,
99         "invalid ThumbnailType: %{public}d", type);
100     std::string thumbDir;
101     if (!IsExThumbType(type)) {
102         thumbDir = GetThumbnailDir(data);
103     } else {
104         thumbDir = GetThumbExDir(data);
105     }
106     CHECK_AND_RETURN_RET_LOG(!thumbDir.empty(), false, "GetThumbnailDir failed. type: %{public}d", type);
107     std::string thumbPath = thumbDir + "/" + THUMB_FILE_NAME_MAP.at(type);
108     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::GetFileSize(thumbPath, size), false,
109         "GetFileSize failed. path: %{public}s", DfxUtils::GetSafePath(thumbPath).c_str());
110     return true;
111 }
112 
DeleteThumbnailDir(const ThumbnailData & data)113 bool ThumbnailFileUtils::DeleteThumbnailDir(const ThumbnailData &data)
114 {
115     string dirName = GetThumbnailDir(data);
116     CHECK_AND_RETURN_RET_LOG(!dirName.empty(), false, "Path:%{public}s is invalid",
117         DfxUtils::GetSafePath(data.path).c_str());
118     CHECK_AND_RETURN_RET_LOG(RemoveDirectoryAndFile(dirName), false, "Failed to remove path: %{public}s",
119         DfxUtils::GetSafePath(dirName).c_str());
120     return true;
121 }
122 
DeleteAllThumbFiles(const ThumbnailData & data)123 bool ThumbnailFileUtils::DeleteAllThumbFiles(const ThumbnailData &data)
124 {
125     bool isDelete = true;
126     isDelete = DeleteThumbFile(data, ThumbnailType::THUMB) && isDelete;
127     isDelete = DeleteThumbFile(data, ThumbnailType::THUMB_ASTC) && isDelete;
128     isDelete = DeleteThumbFile(data, ThumbnailType::LCD) && isDelete;
129     isDelete = DeleteThumbExDir(data) && isDelete;
130     isDelete = DeleteBeginTimestampDir(data) && isDelete;
131     return isDelete;
132 }
133 
DeleteMonthAndYearAstc(const ThumbnailData & data)134 bool ThumbnailFileUtils::DeleteMonthAndYearAstc(const ThumbnailData &data)
135 {
136     bool isDelete = true;
137     isDelete = DeleteAstcDataFromKvStore(data, ThumbnailType::MTH_ASTC) && isDelete;
138     isDelete = DeleteAstcDataFromKvStore(data, ThumbnailType::YEAR_ASTC) && isDelete;
139     return isDelete;
140 }
141 
BatchDeleteMonthAndYearAstc(const ThumbnailDataBatch & dataBatch)142 bool ThumbnailFileUtils::BatchDeleteMonthAndYearAstc(const ThumbnailDataBatch &dataBatch)
143 {
144     bool isBatchDeleteSuccess = true;
145     isBatchDeleteSuccess = BatchDeleteAstcData(dataBatch, ThumbnailType::MTH_ASTC) && isBatchDeleteSuccess;
146     isBatchDeleteSuccess = BatchDeleteAstcData(dataBatch, ThumbnailType::YEAR_ASTC) && isBatchDeleteSuccess;
147     return isBatchDeleteSuccess;
148 }
149 
DeleteThumbFile(const ThumbnailData & data,ThumbnailType type)150 bool ThumbnailFileUtils::DeleteThumbFile(const ThumbnailData &data, ThumbnailType type)
151 {
152     string fileName = GetThumbnailPath(data.path, GetThumbnailSuffix(type));
153     CHECK_AND_RETURN_RET_LOG(!fileName.empty(), false, "Path:%{public}s or type:%{public}d is invalid",
154         DfxUtils::GetSafePath(data.path).c_str(), type);
155 
156     CHECK_AND_RETURN_RET(access(fileName.c_str(), F_OK) == 0, true);
157     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::DeleteFile(fileName), false,
158         "Delete file faild, errno:%{public}d, path:%{public}s", errno, DfxUtils::GetSafePath(fileName).c_str());
159     return true;
160 }
161 
DeleteThumbExDir(const ThumbnailData & data)162 bool ThumbnailFileUtils::DeleteThumbExDir(const ThumbnailData &data)
163 {
164     string dirName = GetThumbExDir(data);
165     CHECK_AND_RETURN_RET_LOG(!dirName.empty(), false, "Path:%{public}s is invalid",
166         DfxUtils::GetSafePath(data.path).c_str());
167 
168     CHECK_AND_RETURN_RET_LOG(RemoveDirectoryAndFile(dirName), false,
169         "Failed to delete THM_EX directory, path: %{public}s, id: %{public}s",
170         DfxUtils::GetSafePath(dirName).c_str(), data.id.c_str());
171     return true;
172 }
173 
DeleteBeginTimestampDirCallback(const char * fpath,const struct stat * sb,int32_t typeflag,struct FTW * ftwbuf)174 int32_t DeleteBeginTimestampDirCallback(const char *fpath, const struct stat *sb, int32_t typeflag, struct FTW *ftwbuf)
175 {
176     CHECK_AND_RETURN_RET_LOG(fpath != nullptr && ftwbuf != nullptr, E_ERR, "Fpath or ftwbuf is nullptr");
177     CHECK_AND_RETURN_RET(typeflag == FTW_D || typeflag == FTW_DNR, E_OK);
178     CHECK_AND_RETURN_RET(ftwbuf->level == BEGIN_TIMESTAMP_DIR_LEVEL, E_OK);
179 
180     string path(fpath);
181     string folderName = MediaFileUtils::GetFileName(path);
182     CHECK_AND_RETURN_RET(folderName.find(BEGIN_TIMESTAMP_DIR_PREFIX) == 0, E_OK);
183     CHECK_AND_RETURN_RET_LOG(ThumbnailFileUtils::RemoveDirectoryAndFile(path), E_ERR,
184         "Failed to remove path: %{public}s", DfxUtils::GetSafePath(path).c_str());
185     return E_OK;
186 }
187 
DeleteBeginTimestampDir(const ThumbnailData & data)188 bool ThumbnailFileUtils::DeleteBeginTimestampDir(const ThumbnailData &data)
189 {
190     string dirName = GetThumbnailDir(data);
191     CHECK_AND_RETURN_RET_LOG(!dirName.empty(), false, "Path:%{public}s is invalid",
192         DfxUtils::GetSafePath(data.path).c_str());
193     CHECK_AND_RETURN_RET(access(dirName.c_str(), F_OK) == 0, true);
194 
195     int32_t err = nftw(dirName.c_str(), DeleteBeginTimestampDirCallback, OPEN_FDS, FTW_PHYS);
196     CHECK_AND_RETURN_RET_LOG(err == 0, false, "DeleteBeginTimestampDir failed, errno:%{public}d, "
197         "path: %{public}s, id: %{public}s", errno, DfxUtils::GetSafePath(dirName).c_str(), data.id.c_str());
198     return true;
199 }
200 
CheckRemainSpaceMeetCondition(int32_t freeSizePercentLimit)201 bool ThumbnailFileUtils::CheckRemainSpaceMeetCondition(int32_t freeSizePercentLimit)
202 {
203     static int64_t totalSize = MediaFileUtils::GetTotalSize();
204     if (totalSize <= 0) {
205         totalSize = MediaFileUtils::GetTotalSize();
206     }
207     CHECK_AND_RETURN_RET_LOG(totalSize > 0, false, "Get total size failed, totalSize:%{public}" PRId64, totalSize);
208     int64_t freeSize = MediaFileUtils::GetFreeSize();
209     CHECK_AND_RETURN_RET_LOG(freeSize > 0, false, "Get free size failed, freeSize:%{public}" PRId64, freeSize);
210     int32_t freeSizePercent = static_cast<int32_t>(freeSize * 100 / totalSize);
211     CHECK_AND_RETURN_RET_LOG(freeSizePercent > freeSizePercentLimit, false,
212         "Check free size failed, totalSize:%{public}" PRId64 ", freeSize:%{public}" PRId64 ", "
213         "freeSizePercentLimit:%{public}d", totalSize, freeSize, freeSizePercentLimit);
214     return true;
215 }
216 
GetKvStore(const ThumbnailType & type)217 std::shared_ptr<MediaLibraryKvStore> GetKvStore(const ThumbnailType &type)
218 {
219     if (type == ThumbnailType::MTH_ASTC) {
220         return MediaLibraryKvStoreManager::GetInstance()
221             .GetKvStore(KvStoreRoleType::OWNER, KvStoreValueType::MONTH_ASTC);
222     } else if (type == ThumbnailType::YEAR_ASTC) {
223         return MediaLibraryKvStoreManager::GetInstance()
224             .GetKvStore(KvStoreRoleType::OWNER, KvStoreValueType::YEAR_ASTC);
225     } else {
226         MEDIA_ERR_LOG("Invalid thumbnailType, type:%{public}d", type);
227         return nullptr;
228     }
229 }
230 
DeleteAstcDataFromKvStore(const ThumbnailData & data,const ThumbnailType & type)231 bool ThumbnailFileUtils::DeleteAstcDataFromKvStore(const ThumbnailData &data, const ThumbnailType &type)
232 {
233     string key;
234     if (!MediaFileUtils::GenerateKvStoreKey(data.id, data.dateTaken, key)) {
235         MEDIA_ERR_LOG("GenerateKvStoreKey failed, id:%{public}s", data.id.c_str());
236         return false;
237     }
238 
239     std::shared_ptr<MediaLibraryKvStore> kvStore = GetKvStore(type);
240     CHECK_AND_RETURN_RET_LOG(kvStore != nullptr, false, "KvStore is nullptr");
241     int status = kvStore->Delete(key);
242     return status == E_OK;
243 }
244 
BatchDeleteAstcData(const ThumbnailDataBatch & dataBatch,const ThumbnailType & type)245 bool ThumbnailFileUtils::BatchDeleteAstcData(const ThumbnailDataBatch &dataBatch, const ThumbnailType &type)
246 {
247     size_t dataBatchSize = dataBatch.ids.size();
248     CHECK_AND_RETURN_RET_LOG(dataBatchSize == dataBatch.dateTakens.size(), false, "Failed to check dataBatch");
249     if (dataBatchSize == 0) {
250         return true;
251     }
252 
253     vector<string> keys;
254     for (size_t i = 0; i < dataBatchSize; i++) {
255         string key;
256         if (!MediaFileUtils::GenerateKvStoreKey(dataBatch.ids[i], dataBatch.dateTakens[i], key)) {
257             MEDIA_ERR_LOG("GenerateKvStoreKey failed, id:%{public}s", dataBatch.ids[i].c_str());
258             continue;
259         }
260         keys.push_back(key);
261     }
262 
263     std::shared_ptr<MediaLibraryKvStore> kvStore = GetKvStore(type);
264     CHECK_AND_RETURN_RET_LOG(kvStore != nullptr, false, "KvStore is nullptr");
265     constexpr int32_t ONE_BATCH_SIZE = 100;
266     bool batchDeleteSuccess = true;
267     size_t totalSize = keys.size();
268     for (size_t i = 0; i < totalSize; i += ONE_BATCH_SIZE) {
269         size_t endIndex = std::min(i + ONE_BATCH_SIZE, totalSize);
270         vector<string> batchKeys(keys.begin() + i, keys.begin() + endIndex);
271         int32_t status = kvStore->DeleteBatch(batchKeys);
272         if (status != E_OK) {
273             string startKey = batchKeys.front();
274             string endKey = batchKeys.back();
275             MEDIA_ERR_LOG("Failed to delete batch from %{public}s to %{public}s, status:%{public}d",
276                 startKey.c_str(), endKey.c_str(), status);
277             batchDeleteSuccess = false;
278         }
279     }
280     return batchDeleteSuccess;
281 }
282 
RemoveDirectoryAndFile(const std::string & path)283 bool ThumbnailFileUtils::RemoveDirectoryAndFile(const std::string &path)
284 {
285     CHECK_AND_RETURN_RET_LOG(!path.empty(), false, "Path is empty");
286     CHECK_AND_RETURN_RET(access(path.c_str(), F_OK) == 0, true);
287 
288     std::error_code errCode;
289     std::uintmax_t num = std::filesystem::remove_all(path, errCode);
290     CHECK_AND_RETURN_RET_LOG(errCode.value() == E_OK, false,
291         "Remove path failed, errno:%{public}d, path:%{public}s, errCode:%{public}d",
292         errno, DfxUtils::GetSafePath(path).c_str(), errCode.value());
293     return true;
294 }
295 
IsWifiConnected()296 bool ThumbnailFileUtils::IsWifiConnected()
297 {
298     bool isWifiConnected = false;
299 #ifdef HAS_WIFI_MANAGER_PART
300     auto wifiDevicePtr = Wifi::WifiDevice::GetInstance(WIFI_DEVICE_ABILITY_ID);
301     CHECK_AND_RETURN_RET_LOG(wifiDevicePtr != nullptr, false, "WifiDevicePtr is nullptr");
302     int32_t ret = wifiDevicePtr->IsConnected(isWifiConnected);
303     CHECK_AND_RETURN_RET_LOG(ret == Wifi::WIFI_OPT_SUCCESS, false, "Get Is Connnected Fail: %{public}d", ret);
304 #endif
305     return isWifiConnected;
306 }
307 } // namespace Media
308 } // namespace OHOS