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 #define MLOG_TAG "MtpMediaLibrary"
16
17 #include "mtp_media_library.h"
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <sys/time.h>
21 #include <shared_mutex>
22 #include "mtp_data_utils.h"
23 #include "media_file_utils.h"
24 #include "media_log.h"
25 #include "medialibrary_errno.h"
26 #include "mtp_error_utils.h"
27 #include "mtp_file_observer.h"
28 #include "mtp_packet_tools.h"
29 #include "mtp_storage_manager.h"
30 #include "image_packer.h"
31 #include "avmetadatahelper.h"
32
33 namespace OHOS {
34 namespace Media {
35 namespace {
36 using ReadLock = std::shared_lock<std::shared_mutex>;
37 using WriteLock = std::lock_guard<std::shared_mutex>;
38 const std::string PUBLIC_REAL_PATH_PRE = "/storage/media/";
39 const std::string PUBLIC_REAL_PATH_END = "/local/files/Docs";
40 const std::string PUBLIC_DOC = "/storage/media/local/files/Docs";
41 const std::string SD_DOC = "/storage/External";
42 const std::string TRASH_DIR_NAME = "/storage/media/local/files/Docs/.Trash";
43 const std::string RECENT_DIR_NAME = "/storage/media/local/files/Docs/.Recent";
44 const std::string THUMBS_DIR_NAME = "/storage/media/local/files/Docs/.thumbs";
45 const std::string BACKUP_DIR_NAME = "/storage/media/local/files/Docs/.backup";
46 const std::string APPDATA_DIR_NAME = "/storage/media/local/files/Docs/appdata";
47 const std::string DESKTOP_NAME = "/storage/media/local/files/Docs/Desktop";
48 const std::string PATH_SEPARATOR = "/";
49 constexpr uint32_t BASE_USER_RANGE = 200000;
50 constexpr int32_t NORMAL_WIDTH = 256;
51 constexpr int32_t NORMAL_HEIGHT = 256;
52 constexpr int32_t COMPRE_SIZE_LEVEL_2 = 204800;
53 constexpr int32_t PATH_TIMEVAL_MAX = 2;
54 const std::string THUMBNAIL_FORMAT = "image/jpeg";
55 static constexpr uint8_t THUMBNAIL_MID = 90;
56 static std::unordered_map<uint32_t, std::string> handleToPathMap;
57 static std::unordered_map<std::string, uint32_t> pathToHandleMap;
58 static std::shared_mutex g_mutex;
59 enum HANDLE_DEFAULT_ID : uint32_t {
60 DEFAULT_PARENT_ID = 0,
61 START_ID
62 };
63
64 static std::unordered_map<uint32_t, std::string> storageIdToPathMap;
65 enum STORAGE_ID : uint32_t {
66 INNER_STORAGE_ID = 1,
67 SD_START_ID = INNER_STORAGE_ID + 1,
68 SD_END_ID = SD_START_ID + 127
69 };
70 } // namespace
71
72 std::atomic<uint32_t> MtpMediaLibrary::id_ = 0;
73 std::shared_ptr<MtpMediaLibrary> MtpMediaLibrary::instance_ = nullptr;
74
GetInstance()75 std::shared_ptr<MtpMediaLibrary> MtpMediaLibrary::GetInstance()
76 {
77 static std::once_flag oc;
78 std::call_once(oc, []() {
79 instance_ = std::make_shared<MtpMediaLibrary>();
80 if (instance_ != nullptr) {
81 instance_->Init();
82 }
83 });
84 return instance_;
85 }
86
Init()87 void MtpMediaLibrary::Init()
88 {
89 id_ = START_ID;
90 {
91 WriteLock lock(g_mutex);
92 handleToPathMap.clear();
93 pathToHandleMap.clear();
94 storageIdToPathMap.clear();
95 std::unordered_map<uint32_t, std::string>().swap(handleToPathMap);
96 std::unordered_map<std::string, uint32_t>().swap(pathToHandleMap);
97 std::unordered_map<uint32_t, std::string>().swap(storageIdToPathMap);
98 }
99 // clear all storages, otherwise it maybe has duty data.
100 auto manager = MtpStorageManager::GetInstance();
101 if (manager != nullptr) {
102 manager->ClearStorages();
103 }
104 }
105
Clear()106 void MtpMediaLibrary::Clear()
107 {
108 MEDIA_INFO_LOG("MtpMediaLibrary::Clear is called");
109 Init();
110 }
111
GetId()112 uint32_t MtpMediaLibrary::GetId()
113 {
114 return id_++;
115 }
116
IsHiddenDirectory(const std::string & dir)117 static bool IsHiddenDirectory(const std::string &dir)
118 {
119 CHECK_AND_RETURN_RET_LOG(!dir.empty(), false, "dir is empty");
120 static const std::unordered_map<std::string, uint8_t> hiddenDirs = {
121 {TRASH_DIR_NAME, 0},
122 {RECENT_DIR_NAME, 0},
123 {THUMBS_DIR_NAME, 0},
124 {BACKUP_DIR_NAME, 0},
125 {APPDATA_DIR_NAME, 0},
126 {DESKTOP_NAME, 0}
127 };
128 CHECK_AND_RETURN_RET(hiddenDirs.find(dir) != hiddenDirs.end(), false);
129 return true;
130 }
131
IsRootPath(const std::string & path)132 static bool IsRootPath(const std::string &path)
133 {
134 CHECK_AND_RETURN_RET_LOG(!path.empty(), false, "path is empty");
135 for (const auto &it : storageIdToPathMap) {
136 CHECK_AND_RETURN_RET(path.compare(it.second) != 0, true);
137 }
138 return false;
139 }
140
GetStatTime(const std::string & fromPath,const std::string & toPath,bool recursive,std::unordered_map<std::string,std::pair<long,long>> & statTimeMap)141 static void GetStatTime(const std::string &fromPath, const std::string &toPath, bool recursive,
142 std::unordered_map<std::string, std::pair<long, long>> &statTimeMap)
143 {
144 std::error_code ec;
145 std::vector<std::string> pathList;
146 pathList.push_back(fromPath);
147 if (recursive && sf::is_directory(fromPath, ec)) {
148 for (const auto& entry : sf::recursive_directory_iterator(fromPath, ec)) {
149 if (ec.value() == MTP_SUCCESS) {
150 pathList.push_back(entry.path().string());
151 }
152 }
153 }
154
155 struct stat statInfo = {};
156 for (const auto &path : pathList) {
157 if (stat(path.c_str(), &statInfo) != 0) {
158 MEDIA_WARN_LOG("stat fromPath:%{public}s failed", path.c_str());
159 continue;
160 }
161 std::string to = path;
162 to.replace(0, fromPath.size(), toPath);
163 statTimeMap[to].first = statInfo.st_ctime;
164 statTimeMap[to].second = statInfo.st_mtime;
165 }
166 }
167
SetStatTime(const std::unordered_map<std::string,std::pair<long,long>> & statTimeMap)168 static void SetStatTime(const std::unordered_map<std::string, std::pair<long, long>> &statTimeMap)
169 {
170 struct timeval times[PATH_TIMEVAL_MAX] = { { 0, 0 }, { 0, 0 } };
171 for (auto it = statTimeMap.begin(); it != statTimeMap.end(); it++) {
172 times[0].tv_sec = it->second.first;
173 times[1].tv_sec = it->second.second;
174 if (utimes(it->first.c_str(), times) != 0) {
175 MEDIA_WARN_LOG("utimes toPath:%{public}s failed", it->first.c_str());
176 }
177 }
178 }
179
ScanDirNoDepth(const std::string & root,std::shared_ptr<UInt32List> & out)180 int32_t MtpMediaLibrary::ScanDirNoDepth(const std::string &root, std::shared_ptr<UInt32List> &out)
181 {
182 CHECK_AND_RETURN_RET_LOG(out != nullptr, E_ERR, "out is nullptr");
183 CHECK_AND_RETURN_RET_LOG(access(root.c_str(), R_OK) == 0, E_ERR, "access failed root[%{public}s]", root.c_str());
184 bool cond = (!sf::exists(root) || !sf::is_directory(root));
185 CHECK_AND_RETURN_RET_LOG(!cond, E_ERR,
186 "MtpMediaLibrary::ScanDirNoDepth root[%{public}s] is not exists", root.c_str());
187 std::error_code ec;
188 for (const auto& entry : sf::directory_iterator(root, ec)) {
189 if (ec.value() != MTP_SUCCESS) {
190 continue;
191 }
192 // show not recycle dir
193 if (sf::is_directory(entry.path(), ec) && IsHiddenDirectory(entry.path().string())) {
194 continue;
195 }
196 uint32_t id = AddPathToMap(entry.path().string());
197 out->push_back(id);
198 }
199 return MTP_SUCCESS;
200 }
201
AddToHandlePathMap(const std::string & path,const uint32_t id)202 void MtpMediaLibrary::AddToHandlePathMap(const std::string &path, const uint32_t id)
203 {
204 if (handleToPathMap.find(id) != handleToPathMap.end()) {
205 handleToPathMap.erase(id);
206 }
207 if (pathToHandleMap.find(path) != pathToHandleMap.end()) {
208 pathToHandleMap.erase(path);
209 }
210 pathToHandleMap.emplace(path, id);
211 handleToPathMap.emplace(id, path);
212 }
213
ModifyHandlePathMap(const std::string & from,const std::string & to)214 void MtpMediaLibrary::ModifyHandlePathMap(const std::string &from, const std::string &to)
215 {
216 auto it = pathToHandleMap.find(from);
217 CHECK_AND_RETURN_LOG(it != pathToHandleMap.end(), "MtpMediaLibrary::ModifyHandlePathMap from not found");
218 uint32_t id = it->second;
219 pathToHandleMap.erase(it);
220 pathToHandleMap.emplace(to, id);
221
222 auto iter = handleToPathMap.find(id);
223 if (iter != handleToPathMap.end()) {
224 handleToPathMap.erase(iter);
225 handleToPathMap.emplace(id, to);
226 }
227 }
228
ModifyPathHandleMap(const std::string & path,const uint32_t id)229 void MtpMediaLibrary::ModifyPathHandleMap(const std::string &path, const uint32_t id)
230 {
231 auto it = pathToHandleMap.find(path);
232 CHECK_AND_RETURN_LOG(it != pathToHandleMap.end(), "MtpMediaLibrary::ModifyPathHandleMap from not found");
233
234 uint32_t originalId = it->second;
235 pathToHandleMap.erase(it);
236 pathToHandleMap.emplace(path, id);
237
238 auto iter = handleToPathMap.find(originalId);
239 if (iter != handleToPathMap.end()) {
240 handleToPathMap.erase(iter);
241 handleToPathMap.emplace(id, path);
242 }
243 }
244
StartsWith(const std::string & str,const std::string & prefix)245 bool MtpMediaLibrary::StartsWith(const std::string& str, const std::string& prefix)
246 {
247 if (prefix.size() > str.size() || prefix.empty() || str.empty()) {
248 MEDIA_DEBUG_LOG("MtpMediaLibrary::StartsWith prefix size error");
249 return false;
250 }
251
252 for (size_t i = 0; i < prefix.size(); ++i) {
253 if (str[i] != prefix[i]) {
254 return false;
255 }
256 }
257 return true;
258 }
259
DeleteHandlePathMap(const std::string & path,const uint32_t id)260 void MtpMediaLibrary::DeleteHandlePathMap(const std::string &path, const uint32_t id)
261 {
262 WriteLock lock(g_mutex);
263 if (pathToHandleMap.find(path) != pathToHandleMap.end()) {
264 pathToHandleMap.erase(path);
265 }
266 if (handleToPathMap.find(id) != handleToPathMap.end()) {
267 handleToPathMap.erase(id);
268 }
269 }
270
ObserverAddPathToMap(const std::string & path)271 uint32_t MtpMediaLibrary::ObserverAddPathToMap(const std::string &path)
272 {
273 MEDIA_DEBUG_LOG("MtpMediaLibrary::ObserverAddPathToMap path[%{public}s]", path.c_str());
274 {
275 WriteLock lock(g_mutex);
276 return AddPathToMap(path);
277 }
278 }
279
ObserverDeletePathToMap(const std::string & path)280 void MtpMediaLibrary::ObserverDeletePathToMap(const std::string &path)
281 {
282 MEDIA_DEBUG_LOG("MtpMediaLibrary::ObserverDeletePathToMap path[%{public}s]", path.c_str());
283 {
284 WriteLock lock(g_mutex);
285 auto it = pathToHandleMap.find(path);
286 if (it == pathToHandleMap.end()) {
287 return;
288 }
289 ErasePathInfo(it->second, path);
290 }
291 }
292
MoveHandlePathMap(const std::string & from,const std::string & to)293 void MtpMediaLibrary::MoveHandlePathMap(const std::string &from, const std::string &to)
294 {
295 std::string prefix = from + "/";
296 for (auto it = pathToHandleMap.begin(); it != pathToHandleMap.end();) {
297 if (StartsWith(it->first, prefix)) {
298 uint32_t eachId = it->second;
299 std::string eachStr = it->first;
300 it = pathToHandleMap.erase(it);
301
302 std::string eachSuffixString = eachStr.substr(prefix.size());
303 std::string newPath = to + "/" + eachSuffixString;
304 pathToHandleMap.emplace(newPath, eachId);
305
306 auto iter = handleToPathMap.find(eachId);
307 if (iter != handleToPathMap.end()) {
308 handleToPathMap.erase(iter);
309 handleToPathMap.emplace(eachId, newPath);
310 }
311 } else {
312 ++it;
313 }
314 }
315 }
316
MoveRepeatDirHandlePathMap(const std::string & from,const std::string & to)317 void MtpMediaLibrary::MoveRepeatDirHandlePathMap(const std::string &from, const std::string &to)
318 {
319 std::string prefix = from + "/";
320 for (auto it = pathToHandleMap.begin(); it != pathToHandleMap.end();) {
321 if (StartsWith(it->first, prefix)) {
322 uint32_t eachId = it->second;
323 std::string eachStr = it->first;
324 it = pathToHandleMap.erase(it);
325
326 std::string eachSuffixString = eachStr.substr(prefix.size());
327 std::string newPath = to + "/" + eachSuffixString;
328 pathToHandleMap.emplace(newPath, eachId);
329
330 auto iter = handleToPathMap.find(eachId);
331 if (iter != handleToPathMap.end()) {
332 handleToPathMap.erase(iter);
333 handleToPathMap.emplace(eachId, newPath);
334 }
335 } else {
336 ++it;
337 }
338 }
339 uint32_t originToId = pathToHandleMap[to];
340 auto iterator = pathToHandleMap.find(from);
341 if (iterator != pathToHandleMap.end()) {
342 uint32_t id = iterator->second;
343 pathToHandleMap.erase(iterator);
344 pathToHandleMap[to] = id;
345
346 auto iter = handleToPathMap.find(id);
347 if (iter != handleToPathMap.end()) {
348 handleToPathMap.erase(originToId);
349 handleToPathMap[id] = to;
350 }
351 }
352 }
353
GetHandles(int32_t parentId,std::vector<int> & outHandles,MediaType mediaType)354 int32_t MtpMediaLibrary::GetHandles(int32_t parentId, std::vector<int> &outHandles, MediaType mediaType)
355 {
356 MEDIA_DEBUG_LOG("MtpMediaLibrary::GetHandles parent[%{public}d]", parentId);
357 std::string path("");
358 CHECK_AND_RETURN_RET_LOG(GetPathById(parentId, path) == MTP_SUCCESS,
359 MtpErrorUtils::SolveGetHandlesError(E_HAS_DB_ERROR), "MtpMediaLibrary::GetHandles parent not found");
360 std::shared_ptr<UInt32List> out = std::make_shared<UInt32List>();
361 {
362 WriteLock lock(g_mutex);
363 ScanDirNoDepth(path, out);
364 }
365 for (const auto &handle : *out) {
366 outHandles.push_back(handle);
367 }
368 return MTP_SUCCESS;
369 }
370
GetHandles(const std::shared_ptr<MtpOperationContext> & context,std::shared_ptr<UInt32List> & outHandles)371 int32_t MtpMediaLibrary::GetHandles(const std::shared_ptr<MtpOperationContext> &context,
372 std::shared_ptr<UInt32List> &outHandles)
373 {
374 CHECK_AND_RETURN_RET_LOG(context != nullptr,
375 MtpErrorUtils::SolveGetHandlesError(E_HAS_DB_ERROR), "context is nullptr");
376 uint32_t parentId = context->parent;
377 std::string path("");
378 CHECK_AND_RETURN_RET_LOG(GetPathByContextParent(context, path) == MTP_SUCCESS,
379 MtpErrorUtils::SolveGetHandlesError(E_HAS_DB_ERROR),
380 "MtpMediaLibrary::GetHandles parent[%{public}d] not found", parentId);
381 MEDIA_DEBUG_LOG("MtpMediaLibrary::GetHandles path[%{public}s]", path.c_str());
382 int32_t errCode;
383 {
384 WriteLock lock(g_mutex);
385 errCode = ScanDirNoDepth(path, outHandles);
386 }
387 return errCode;
388 }
389
GetParentId(const std::string & path)390 uint32_t MtpMediaLibrary::GetParentId(const std::string &path)
391 {
392 ReadLock lock(g_mutex);
393 auto parentPath = sf::path(path).parent_path().string();
394 auto it = pathToHandleMap.find(parentPath);
395 CHECK_AND_RETURN_RET(it != pathToHandleMap.end(), 0);
396 return it->second;
397 }
398
GetSizeFromOfft(const off_t & size)399 uint32_t MtpMediaLibrary::GetSizeFromOfft(const off_t &size)
400 {
401 return size > std::numeric_limits<uint32_t>::max() ? std::numeric_limits<uint32_t>::max() : size;
402 }
403
GetObjectInfo(const std::shared_ptr<MtpOperationContext> & context,std::shared_ptr<ObjectInfo> & outObjectInfo)404 int32_t MtpMediaLibrary::GetObjectInfo(const std::shared_ptr<MtpOperationContext> &context,
405 std::shared_ptr<ObjectInfo> &outObjectInfo)
406 {
407 bool cond = (context == nullptr || context->handle <= 0 || outObjectInfo == nullptr);
408 CHECK_AND_RETURN_RET_LOG(!cond, MtpErrorUtils::SolveGetObjectInfoError(E_HAS_DB_ERROR), "handle error");
409 MEDIA_DEBUG_LOG("MtpMediaLibrary::GetObjectInfo storageID[%{public}d]", context->storageID);
410 std::string path("");
411 CHECK_AND_RETURN_RET_LOG(GetPathById(context->handle, path) == MTP_SUCCESS,
412 MtpErrorUtils::SolveGetObjectInfoError(E_HAS_DB_ERROR), "MtpMediaLibrary::GetObjectInfo handle not found");
413 outObjectInfo->handle = context->handle;
414 outObjectInfo->name = sf::path(path).filename().string();
415 outObjectInfo->parent = GetParentId(path);
416 outObjectInfo->storageID = context->storageID;
417 MtpDataUtils::GetMtpFormatByPath(path, outObjectInfo->format);
418 MediaType mediaType;
419 MtpDataUtils::GetMediaTypeByformat(outObjectInfo->format, mediaType);
420 if (mediaType == MediaType::MEDIA_TYPE_IMAGE || mediaType == MediaType::MEDIA_TYPE_VIDEO) {
421 outObjectInfo->thumbCompressedSize = COMPRE_SIZE_LEVEL_2;
422 outObjectInfo->thumbFormat = MTP_FORMAT_EXIF_JPEG_CODE;
423 outObjectInfo->thumbPixelHeight = NORMAL_HEIGHT;
424 outObjectInfo->thumbPixelWidth = NORMAL_WIDTH;
425 }
426
427 std::error_code ec;
428 if (sf::is_directory(path, ec)) {
429 outObjectInfo->format = MTP_FORMAT_ASSOCIATION_CODE;
430 }
431 struct stat statInfo;
432 CHECK_AND_RETURN_RET_LOG(stat(path.c_str(), &statInfo) == 0,
433 MtpErrorUtils::SolveGetObjectInfoError(E_HAS_DB_ERROR), "MtpMediaLibrary::GetObjectInfo stat failed");
434 outObjectInfo->size = GetSizeFromOfft(statInfo.st_size);
435 outObjectInfo->dateCreated = statInfo.st_ctime;
436 outObjectInfo->dateModified = statInfo.st_mtime;
437 return MtpErrorUtils::SolveGetObjectInfoError(E_SUCCESS);
438 }
439
IsExistObject(const std::shared_ptr<MtpOperationContext> & context)440 bool MtpMediaLibrary::IsExistObject(const std::shared_ptr<MtpOperationContext> &context)
441 {
442 CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context is nullptr");
443
444 std::string realPath("");
445 CHECK_AND_RETURN_RET_LOG(GetPathById(context->handle, realPath) == MTP_SUCCESS, false,
446 "MtpMediaLibrary::IsExistObject handle not found");
447 bool ret = sf::exists(realPath);
448 if (!ret) {
449 DeleteHandlePathMap(realPath, context->handle);
450 }
451 return ret;
452 }
453
GetFd(const std::shared_ptr<MtpOperationContext> & context,int32_t & outFd,bool forWrite)454 int32_t MtpMediaLibrary::GetFd(const std::shared_ptr<MtpOperationContext> &context, int32_t &outFd, bool forWrite)
455 {
456 MEDIA_INFO_LOG("MtpMediaLibrary::GetFd");
457 CHECK_AND_RETURN_RET_LOG(context != nullptr,
458 MtpErrorUtils::SolveGetFdError(E_HAS_DB_ERROR), "context is nullptr");
459 std::string realPath("");
460 CHECK_AND_RETURN_RET_LOG(GetPathById(context->handle, realPath) == MTP_SUCCESS,
461 MtpErrorUtils::SolveGetFdError(E_HAS_DB_ERROR), "MtpMediaLibrary::GetFd handle not found");
462
463 std::error_code ec;
464 realPath = sf::weakly_canonical(realPath, ec);
465 CHECK_AND_RETURN_RET_LOG(ec.value() == MTP_SUCCESS,
466 MtpErrorUtils::SolveGetFdError(E_HAS_FS_ERROR), "MtpMediaLibrary::GetFd normalized realPath failed");
467
468 int mode = O_RDONLY;
469 if (forWrite) {
470 mode = sf::exists(realPath, ec) ? O_RDWR : (O_RDWR | O_CREAT);
471 }
472
473 outFd = open(realPath.c_str(), mode);
474 MEDIA_INFO_LOG("MTP:file %{public}s fd %{public}d", realPath.c_str(), outFd);
475 CHECK_AND_RETURN_RET(outFd <= 0, MtpErrorUtils::SolveGetFdError(E_SUCCESS));
476 return MtpErrorUtils::SolveGetFdError(E_HAS_FS_ERROR);
477 }
478
CompressImage(PixelMap & pixelMap,std::vector<uint8_t> & data)479 bool MtpMediaLibrary::CompressImage(PixelMap &pixelMap, std::vector<uint8_t> &data)
480 {
481 PackOption option = {
482 .format = THUMBNAIL_FORMAT,
483 .quality = THUMBNAIL_MID,
484 .numberHint = 1
485 };
486 data.resize(pixelMap.GetByteCount());
487
488 ImagePacker imagePacker;
489 uint32_t errorCode = imagePacker.StartPacking(data.data(), data.size(), option);
490 CHECK_AND_RETURN_RET_LOG(errorCode == E_SUCCESS, false, "Failed to StartPacking %{public}d", errorCode);
491
492 errorCode = imagePacker.AddImage(pixelMap);
493 CHECK_AND_RETURN_RET_LOG(errorCode == E_SUCCESS, false, "Failed to AddImage %{public}d", errorCode);
494
495 int64_t packedSize = 0;
496 errorCode = imagePacker.FinalizePacking(packedSize);
497 CHECK_AND_RETURN_RET_LOG(errorCode == E_SUCCESS, false, "Failed to FinalizePacking %{public}d", errorCode);
498
499 data.resize(packedSize);
500 return true;
501 }
502
GetVideoThumb(const std::shared_ptr<MtpOperationContext> & context,std::shared_ptr<UInt8List> & outThumb)503 int32_t MtpMediaLibrary::GetVideoThumb(const std::shared_ptr<MtpOperationContext> &context,
504 std::shared_ptr<UInt8List> &outThumb)
505 {
506 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_CONTEXT_IS_NULL, "context is nullptr");
507
508 shared_ptr<AVMetadataHelper> avMetadataHelper = AVMetadataHelperFactory::CreateAVMetadataHelper();
509 CHECK_AND_RETURN_RET_LOG(avMetadataHelper != nullptr, MTP_ERROR_NO_THUMBNAIL_PRESENT,
510 "avMetadataHelper is nullptr");
511
512 int32_t fd = 0;
513 int error = GetFd(context, fd);
514 CHECK_AND_RETURN_RET_LOG(error == MTP_SUCCESS, MTP_ERROR_NO_THUMBNAIL_PRESENT, "GetFd failed");
515
516 struct stat64 st;
517 int32_t ret = fstat64(fd, &st);
518 CondCloseFd(ret != 0, fd);
519 CHECK_AND_RETURN_RET_LOG(ret == 0, MTP_ERROR_NO_THUMBNAIL_PRESENT, "Get file state failed, err %{public}d", errno);
520
521 int64_t length = static_cast<int64_t>(st.st_size);
522 ret = avMetadataHelper->SetSource(fd, 0, length, AV_META_USAGE_PIXEL_MAP);
523 CondCloseFd(ret != 0, fd);
524 CHECK_AND_RETURN_RET_LOG(ret == 0, MTP_ERROR_NO_THUMBNAIL_PRESENT, "SetSource failed, ret %{public}d", ret);
525
526 PixelMapParams param = {
527 .dstWidth = NORMAL_WIDTH,
528 .dstHeight = NORMAL_HEIGHT,
529 .colorFormat = PixelFormat::RGBA_8888
530 };
531 shared_ptr<PixelMap> sPixelMap = avMetadataHelper->FetchFrameYuv(0,
532 AVMetadataQueryOption::AV_META_QUERY_NEXT_SYNC, param);
533 CondCloseFd(sPixelMap == nullptr, fd);
534 CHECK_AND_RETURN_RET_LOG(sPixelMap != nullptr, MTP_ERROR_NO_THUMBNAIL_PRESENT, "sPixelMap is nullptr");
535
536 sPixelMap->SetAlphaType(AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL);
537 CloseFd(context, fd);
538 bool isCompressImageSuccess = CompressImage(*sPixelMap.get(), *outThumb);
539 CHECK_AND_RETURN_RET_LOG(isCompressImageSuccess == true, MTP_ERROR_NO_THUMBNAIL_PRESENT, "CompressImage is fail");
540 return MTP_SUCCESS;
541 }
542
GetPictureThumb(const std::shared_ptr<MtpOperationContext> & context,std::shared_ptr<UInt8List> & outThumb)543 int32_t MtpMediaLibrary::GetPictureThumb(const std::shared_ptr<MtpOperationContext> &context,
544 std::shared_ptr<UInt8List> &outThumb)
545 {
546 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_CONTEXT_IS_NULL, "context is nullptr");
547
548 int32_t fd = 0;
549 uint32_t errorCode = MTP_SUCCESS;
550 errorCode = static_cast<uint32_t>(GetFd(context, fd));
551 CHECK_AND_RETURN_RET_LOG(errorCode == MTP_SUCCESS, MTP_ERROR_NO_THUMBNAIL_PRESENT, "GetFd failed");
552
553 SourceOptions opts;
554 std::unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(fd, opts, errorCode);
555 CondCloseFd(imageSource == nullptr, fd);
556 CHECK_AND_RETURN_RET_LOG(imageSource != nullptr, MTP_ERROR_NO_THUMBNAIL_PRESENT, "imageSource is nullptr");
557
558 DecodeOptions decodeOpts;
559 decodeOpts.desiredSize = {
560 .width = NORMAL_WIDTH,
561 .height = NORMAL_HEIGHT,
562 };
563
564 std::unique_ptr<PixelMap> cropPixelMap = imageSource->CreatePixelMap(decodeOpts, errorCode);
565 CondCloseFd(cropPixelMap == nullptr, fd);
566 CHECK_AND_RETURN_RET_LOG(cropPixelMap != nullptr, MTP_ERROR_NO_THUMBNAIL_PRESENT, "cropPixelMap is nullptr");
567
568 CloseFd(context, fd);
569 bool isCompressImageSuccess = CompressImage(*cropPixelMap, *outThumb);
570 CHECK_AND_RETURN_RET_LOG(isCompressImageSuccess == true, MTP_ERROR_NO_THUMBNAIL_PRESENT, "CompressImage is fail");
571 return MTP_SUCCESS;
572 }
573
CondCloseFd(const bool condition,const int fd)574 void MtpMediaLibrary::CondCloseFd(const bool condition, const int fd)
575 {
576 if (!condition || fd <= 0) {
577 return;
578 }
579 int32_t ret = close(fd);
580 CHECK_AND_PRINT_LOG(ret == MTP_SUCCESS, "DealFd CloseFd fail!");
581 }
582
583
GetThumb(const std::shared_ptr<MtpOperationContext> & context,std::shared_ptr<UInt8List> & outThumb)584 int32_t MtpMediaLibrary::GetThumb(const std::shared_ptr<MtpOperationContext> &context,
585 std::shared_ptr<UInt8List> &outThumb)
586 {
587 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_CONTEXT_IS_NULL, "context is nullptr");
588 auto it = handleToPathMap.find(context->handle);
589 CHECK_AND_RETURN_RET_LOG(it != handleToPathMap.end(), MtpErrorUtils::SolveGetObjectInfoError(E_HAS_DB_ERROR),
590 "MtpMediaLibrary::GetThumb handle not found");
591
592 uint16_t format;
593 MtpDataUtils::GetMtpFormatByPath(it->second, format);
594 MediaType mediaType;
595 MtpDataUtils::GetMediaTypeByformat(format, mediaType);
596 if (mediaType == MediaType::MEDIA_TYPE_IMAGE) {
597 return GetPictureThumb(context, outThumb);
598 } else if (mediaType == MediaType::MEDIA_TYPE_VIDEO) {
599 return GetVideoThumb(context, outThumb);
600 }
601 return MTP_SUCCESS;
602 }
603
SendObjectInfo(const std::shared_ptr<MtpOperationContext> & context,uint32_t & outStorageID,uint32_t & outParent,uint32_t & outHandle)604 int32_t MtpMediaLibrary::SendObjectInfo(const std::shared_ptr<MtpOperationContext> &context,
605 uint32_t &outStorageID, uint32_t &outParent, uint32_t &outHandle)
606 {
607 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_STORE_NOT_AVAILABLE, "context is nullptr");
608 std::string doc("");
609 CHECK_AND_RETURN_RET_LOG(GetPathByContextParent(context, doc) == MTP_SUCCESS,
610 MtpErrorUtils::SolveSendObjectInfoError(E_HAS_DB_ERROR),
611 "MtpMediaLibrary::SendObjectInfo parent not found");
612
613 std::string path = doc + "/" + context->name;
614 if (context->format == MTP_FORMAT_ASSOCIATION_CODE) {
615 std::error_code ec;
616 bool cond = (!sf::create_directory(path, ec) || ec.value() != MTP_SUCCESS);
617 CHECK_AND_RETURN_RET_LOG(!cond, MtpErrorUtils::SolveGetObjectInfoError(E_HAS_DB_ERROR),
618 "MtpMediaLibrary::GetThumb handle not found");
619 } else {
620 std::error_code ec;
621 path = sf::weakly_canonical(path, ec);
622 CHECK_AND_RETURN_RET_LOG(ec.value() == MTP_SUCCESS, MtpErrorUtils::SolveSendObjectInfoError(E_HAS_FS_ERROR),
623 "MtpMediaLibrary::SendObjectInfo normalized path failed");
624 }
625 uint32_t outObjectHandle;
626 {
627 WriteLock lock(g_mutex);
628 outObjectHandle = AddPathToMap(path);
629 MEDIA_DEBUG_LOG("SendObjectInfo path[%{public}s], handle[%{public}d]", path.c_str(), outObjectHandle);
630 }
631
632 outHandle = outObjectHandle;
633 outStorageID = context->storageID;
634 outParent = context->parent;
635 return MtpErrorUtils::SolveSendObjectInfoError(E_SUCCESS);
636 }
637
GetPathById(const int32_t id,std::string & outPath)638 int32_t MtpMediaLibrary::GetPathById(const int32_t id, std::string &outPath)
639 {
640 MEDIA_DEBUG_LOG("MtpMediaLibrary::GetPathById id[%{public}d]", id);
641 ReadLock lock(g_mutex);
642 auto it = handleToPathMap.find(id);
643 if (it != handleToPathMap.end()) {
644 outPath = it->second;
645 return MTP_SUCCESS;
646 }
647 return E_ERR;
648 }
649
GetPathByContextParent(const std::shared_ptr<MtpOperationContext> & context,std::string & path)650 int32_t MtpMediaLibrary::GetPathByContextParent(const std::shared_ptr<MtpOperationContext> &context, std::string &path)
651 {
652 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_CONTEXT_IS_NULL, "context is nullptr");
653 if (context->parent == 0 || context->parent == MTP_ALL_HANDLE_ID) {
654 auto it = storageIdToPathMap.find(context->storageID);
655 if (it != storageIdToPathMap.end()) {
656 path = it->second;
657 return MTP_SUCCESS;
658 }
659 return E_ERR;
660 }
661 return GetPathById(context->parent, path);
662 }
663
GetIdByPath(const std::string & path,uint32_t & outId)664 int32_t MtpMediaLibrary::GetIdByPath(const std::string &path, uint32_t &outId)
665 {
666 MEDIA_DEBUG_LOG("MtpMediaLibrary::GetIdByPath path[%{public}s]", path.c_str());
667 ReadLock lock(g_mutex);
668 auto it = pathToHandleMap.find(path);
669 if (it != pathToHandleMap.end()) {
670 outId = it->second;
671 return E_SUCCESS;
672 }
673 return E_NO_SUCH_FILE;
674 }
675
GetRealPath(const std::string & path,std::string & outPath)676 int32_t MtpMediaLibrary::GetRealPath(const std::string &path, std::string &outPath)
677 {
678 if (PUBLIC_DOC.compare(path.substr(0, PUBLIC_DOC.size())) == 0) {
679 uid_t uid = getuid() / BASE_USER_RANGE;
680 std::string realPath = PUBLIC_REAL_PATH_PRE + std::to_string(uid) + PUBLIC_REAL_PATH_END;
681 outPath = realPath + path.substr(PUBLIC_DOC.size(), path.size());
682 return MTP_SUCCESS;
683 }
684 if (SD_DOC.compare(path.substr(0, SD_DOC.size())) == 0) {
685 outPath = path;
686 return MTP_SUCCESS;
687 }
688 MEDIA_ERR_LOG("MtpMediaLibrary::GetRealPath path[%{public}s] error", path.c_str());
689 return E_ERR;
690 }
691
MoveObjectSub(const sf::path & fromPath,const sf::path & toPath,const bool & isDir,uint32_t & repeatHandle)692 uint32_t MtpMediaLibrary::MoveObjectSub(const sf::path &fromPath, const sf::path &toPath, const bool &isDir,
693 uint32_t &repeatHandle)
694 {
695 auto it = pathToHandleMap.find(toPath.string());
696 if (it == pathToHandleMap.end()) {
697 if (isDir) {
698 MoveHandlePathMap(fromPath.string(), toPath.string());
699 }
700 ModifyHandlePathMap(fromPath.string(), toPath.string());
701 } else {
702 if (isDir) {
703 uint32_t toHandle = pathToHandleMap.find(toPath.string())->second;
704 MoveRepeatDirHandlePathMap(fromPath, toPath);
705 repeatHandle = toHandle;
706 } else {
707 repeatHandle = pathToHandleMap.find(toPath.string())->second;
708 auto ite = pathToHandleMap.find(fromPath.string());
709 if (ite != pathToHandleMap.end()) {
710 ModifyPathHandleMap(toPath.string(), ite->second);
711 }
712 }
713 }
714 return MTP_SUCCESS;
715 }
716
CrossCopyAfter(bool isDir,const std::string & toPath)717 void CrossCopyAfter(bool isDir, const std::string &toPath)
718 {
719 CHECK_AND_RETURN_LOG(isDir, "MoveObjectAfter not dir");
720 CHECK_AND_RETURN_LOG(!toPath.empty(), "MoveObjectAfter path is empty");
721 std::error_code ec;
722 CHECK_AND_RETURN_LOG(sf::exists(toPath, ec), "MoveObjectAfter path is not exists");
723
724 MtpFileObserver::GetInstance().AddPathToWatchMap(toPath);
725 for (const auto& entry : sf::recursive_directory_iterator(toPath, ec)) {
726 if (ec.value() != MTP_SUCCESS) {
727 continue;
728 }
729 if (sf::is_directory(entry.path(), ec)) {
730 MtpFileObserver::GetInstance().AddPathToWatchMap(entry.path().string());
731 }
732 }
733 }
734
MoveObject(const std::shared_ptr<MtpOperationContext> & context,uint32_t & repeatHandle)735 int32_t MtpMediaLibrary::MoveObject(const std::shared_ptr<MtpOperationContext> &context, uint32_t &repeatHandle)
736 {
737 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_STORE_NOT_AVAILABLE, "context is nullptr");
738 std::string from("");
739 std::string to("");
740 if (GetPathById(context->handle, from) != MTP_SUCCESS || GetPathByContextParent(context, to) != MTP_SUCCESS) {
741 MEDIA_ERR_LOG("MtpMediaLibrary::MoveObject from or to not found");
742 return MtpErrorUtils::SolveMoveObjectError(E_HAS_DB_ERROR);
743 }
744 std::error_code ec;
745 if (!sf::exists(from, ec) || !sf::exists(to, ec)) {
746 MEDIA_ERR_LOG("MtpMediaLibrary::MoveObject from or to path not found");
747 return MtpErrorUtils::SolveMoveObjectError(E_HAS_DB_ERROR);
748 }
749
750 CHECK_AND_RETURN_RET_LOG(sf::is_directory(to, ec), MtpErrorUtils::SolveMoveObjectError(E_HAS_DB_ERROR),
751 "MtpMediaLibrary::MoveObject parent path is not dir");
752 auto fromPath = sf::path(from);
753 auto toPath = sf::path(to) / sf::path(from).filename();
754 bool isDir = sf::is_directory(fromPath, ec);
755 // compare the prefix of the two paths
756 const auto len = PUBLIC_REAL_PATH_PRE.size();
757 bool isSameStorage = from.substr(0, len).compare(to.substr(0, len)) == 0;
758 MEDIA_INFO_LOG("from[%{public}s],to[%{public}s] %{public}d", fromPath.c_str(), toPath.c_str(), isSameStorage);
759 std::unordered_map<std::string, std::pair<long, long>> statTimeMap;
760 GetStatTime(fromPath.string(), toPath.string(), !isSameStorage, statTimeMap);
761 {
762 WriteLock lock(g_mutex);
763 if (isSameStorage) {
764 // move in the same storage
765 sf::rename(fromPath, toPath, ec);
766 } else {
767 // move between different storage
768 sf::copy(fromPath, toPath, sf::copy_options::recursive | sf::copy_options::overwrite_existing, ec);
769 CrossCopyAfter(isDir, toPath);
770 isDir ? sf::remove_all(fromPath, ec) : sf::remove(fromPath, ec);
771 }
772 CHECK_AND_RETURN_RET_LOG(ec.value() == MTP_SUCCESS, MtpErrorUtils::SolveMoveObjectError(E_FAIL),
773 "MtpMediaLibrary::MoveObject failed");
774 MoveObjectSub(fromPath, toPath, isDir, repeatHandle);
775 }
776 SetStatTime(statTimeMap);
777 return MTP_SUCCESS;
778 }
779
CopyObject(const std::shared_ptr<MtpOperationContext> & context,uint32_t & outObjectHandle,uint32_t & oldHandle)780 int32_t MtpMediaLibrary::CopyObject(const std::shared_ptr<MtpOperationContext> &context,
781 uint32_t &outObjectHandle, uint32_t &oldHandle)
782 {
783 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_STORE_NOT_AVAILABLE, "context is nullptr");
784 std::string from("");
785 std::string to("");
786 if (GetPathById(context->handle, from) != MTP_SUCCESS || GetPathByContextParent(context, to) != MTP_SUCCESS) {
787 MEDIA_ERR_LOG("MtpMediaLibrary::CopyObject from or to not found");
788 return MtpErrorUtils::SolveMoveObjectError(E_HAS_DB_ERROR);
789 }
790
791 bool cond = (!sf::exists(from) || !sf::exists(to));
792 CHECK_AND_RETURN_RET_LOG(!cond, MtpErrorUtils::SolveCopyObjectError(E_HAS_DB_ERROR),
793 "MtpMediaLibrary::CopyObject handle or parent path not found");
794 CHECK_AND_RETURN_RET_LOG(sf::is_directory(to), MtpErrorUtils::SolveCopyObjectError(E_HAS_DB_ERROR),
795 "MtpMediaLibrary::CopyObject parent path is not dir");
796 std::error_code ec;
797 auto fromPath = sf::path(from);
798 auto toPath = sf::path(to) / sf::path(from).filename();
799 CHECK_AND_RETURN_RET_LOG(!sf::exists(toPath, ec), MtpErrorUtils::SolveCopyObjectError(E_FILE_EXIST),
800 "MtpMediaLibrary::CopyObject toPath exists");
801 MEDIA_INFO_LOG("from[%{public}s],to[%{public}s]", fromPath.c_str(), toPath.c_str());
802 std::unordered_map<std::string, std::pair<long, long>> statTimeMap;
803 GetStatTime(fromPath.string(), toPath.string(), true, statTimeMap);
804 sf::copy(fromPath, toPath, sf::copy_options::recursive | sf::copy_options::overwrite_existing, ec);
805 CHECK_AND_RETURN_RET_LOG(ec.value() == MTP_SUCCESS, MtpErrorUtils::SolveCopyObjectError(E_FAIL),
806 "MtpMediaLibrary::CopyObject failed");
807 SetStatTime(statTimeMap);
808 {
809 WriteLock lock(g_mutex);
810 outObjectHandle = AddPathToMap(toPath.string());
811 MEDIA_INFO_LOG("CopyObject successful to[%{public}s], handle[%{public}d]", toPath.c_str(), outObjectHandle);
812 }
813 return MTP_SUCCESS;
814 }
815
DeleteObject(const std::shared_ptr<MtpOperationContext> & context)816 int32_t MtpMediaLibrary::DeleteObject(const std::shared_ptr<MtpOperationContext> &context)
817 {
818 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_STORE_NOT_AVAILABLE, "context is nullptr");
819 std::string path("");
820 CHECK_AND_RETURN_RET_LOG(GetPathById(context->handle, path) == MTP_SUCCESS,
821 MtpErrorUtils::SolveDeleteObjectError(E_HAS_DB_ERROR),
822 "MtpMediaLibrary::DeleteObject handle not found");
823 std::error_code ec;
824 if (sf::exists(path, ec) == false) {
825 DeleteHandlePathMap(path, context->handle);
826 return MTP_SUCCESS;
827 }
828 MEDIA_DEBUG_LOG("MtpMediaLibrary::DeleteObject path[%{public}s]", path.c_str());
829 if (sf::is_directory(path, ec)) {
830 sf::remove_all(path, ec);
831 CHECK_AND_RETURN_RET_LOG(ec.value() == MTP_SUCCESS, MtpErrorUtils::SolveDeleteObjectError(E_HAS_DB_ERROR),
832 "MtpMediaLibrary::DeleteObject remove_all failed");
833 {
834 WriteLock lock(g_mutex);
835 ErasePathInfo(context->handle, path);
836 }
837 } else {
838 sf::remove(path, ec);
839 CHECK_AND_RETURN_RET_LOG(ec.value() == MTP_SUCCESS, MtpErrorUtils::SolveDeleteObjectError(E_HAS_DB_ERROR),
840 "MtpMediaLibrary::DeleteObject remove failed");
841 DeleteHandlePathMap(path, context->handle);
842 }
843 return MTP_SUCCESS;
844 }
845
SetObjectPropValue(const std::shared_ptr<MtpOperationContext> & context)846 int32_t MtpMediaLibrary::SetObjectPropValue(const std::shared_ptr<MtpOperationContext> &context)
847 {
848 MEDIA_INFO_LOG("MtpMediaLibrary::SetObjectPropValue");
849 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_INVALID_OBJECTHANDLE, "context is nullptr");
850 std::string colName("");
851 variant<int64_t, std::string> colValue;
852 int32_t errCode = MtpDataUtils::SolveSetObjectPropValueData(context, colName, colValue);
853 CHECK_AND_RETURN_RET_LOG(errCode == 0, errCode, "fail to SolveSetObjectPropValueData");
854 CHECK_AND_RETURN_RET(colName.compare(MEDIA_DATA_DB_PARENT_ID) != 0, MTP_SUCCESS);
855 std::string path("");
856 CHECK_AND_RETURN_RET_LOG(GetPathById(context->handle, path) == MTP_SUCCESS,
857 MtpErrorUtils::SolveObjectPropValueError(E_HAS_DB_ERROR),
858 "MtpMediaLibrary::SetObjectPropValue handle not found");
859
860 std::error_code ec;
861 string to = sf::path(path).parent_path().string() + "/" + get<std::string>(colValue);
862 bool cond = (sf::exists(to, ec) || ec.value() != MTP_SUCCESS);
863 CHECK_AND_RETURN_RET_LOG(!cond, MtpErrorUtils::SolveObjectPropValueError(E_HAS_DB_ERROR),
864 "MtpMediaLibrary::SetObjectPropValue rename failed, file/doc exists");
865 {
866 WriteLock lock(g_mutex);
867 sf::rename(path, to, ec);
868 CHECK_AND_RETURN_RET_LOG(ec.value() == MTP_SUCCESS, MtpErrorUtils::SolveObjectPropValueError(E_HAS_DB_ERROR),
869 "MtpMediaLibrary::SetObjectPropValue rename failed");
870 ModifyHandlePathMap(path, to);
871 if (sf::is_directory(to, ec)) {
872 MoveHandlePathMap(path, to);
873 }
874 }
875 return MTP_SUCCESS;
876 }
877
CloseFd(const std::shared_ptr<MtpOperationContext> & context,int32_t fd)878 int32_t MtpMediaLibrary::CloseFd(const std::shared_ptr<MtpOperationContext> &context, int32_t fd)
879 {
880 MEDIA_DEBUG_LOG("MtpMediaLibrary::CloseFd fd=[%{public}d]", fd);
881 CHECK_AND_RETURN_RET_LOG(fd > 0, E_ERR, "wrong fd");
882 int errCode = close(fd);
883 return MtpErrorUtils::SolveCloseFdError(errCode);
884 }
885
GetHandles(const uint32_t handle,const std::string & root,std::shared_ptr<std::unordered_map<uint32_t,std::string>> & out)886 void MtpMediaLibrary::GetHandles(const uint32_t handle, const std::string &root,
887 std::shared_ptr<std::unordered_map<uint32_t, std::string>> &out)
888 {
889 CHECK_AND_RETURN_LOG(out != nullptr, "out is nullptr");
890 auto it = handleToPathMap.find(handle);
891 if (it == handleToPathMap.end()) {
892 return;
893 }
894 out->emplace(handle, it->second);
895 }
896
GetHandlesMap(const std::shared_ptr<MtpOperationContext> & context)897 std::shared_ptr<std::unordered_map<uint32_t, std::string>> MtpMediaLibrary::GetHandlesMap(
898 const std::shared_ptr<MtpOperationContext> &context)
899 {
900 CHECK_AND_RETURN_RET_LOG(context != nullptr, nullptr, "context is nullptr");
901 auto handlesMap = std::make_shared<std::unordered_map<uint32_t, std::string>>();
902 CHECK_AND_RETURN_RET_LOG(handlesMap != nullptr, nullptr, "handlesMap is nullptr");
903 auto it = storageIdToPathMap.find(context->storageID);
904 const std::string root = (it == storageIdToPathMap.end()) ? PUBLIC_DOC : it->second;
905 if (context->depth == MTP_ALL_DEPTH && (context->handle == 0 || context->handle == MTP_ALL_HANDLE_ID)) {
906 context->handle = MTP_ALL_HANDLE_ID;
907 context->depth = 0;
908 }
909 if (context->handle != 0) {
910 if (context->depth == 0) {
911 if (context->handle == MTP_ALL_HANDLE_ID) {
912 ScanDirTraverseWithType(root, handlesMap);
913 } else {
914 GetHandles(context->handle, root, handlesMap);
915 }
916 }
917 if (context->depth == 1) {
918 if (context->handle == MTP_ALL_HANDLE_ID) {
919 ScanDirWithType(root, handlesMap);
920 } else {
921 auto it = handleToPathMap.find(context->handle);
922 std::string path = (it == handleToPathMap.end()) ? root : it->second;
923 ScanDirWithType(path, handlesMap);
924 }
925 }
926 } else {
927 ScanDirWithType(root, handlesMap);
928 }
929 return handlesMap;
930 }
931
CorrectStorageId(const std::shared_ptr<MtpOperationContext> & context)932 void MtpMediaLibrary::CorrectStorageId(const std::shared_ptr<MtpOperationContext> &context)
933 {
934 CHECK_AND_RETURN_LOG(context != nullptr, "context is nullptr");
935 CHECK_AND_RETURN_LOG(context->handle > 0, "no need correct");
936
937 auto it = handleToPathMap.find(context->handle);
938 CHECK_AND_RETURN_LOG(it != handleToPathMap.end(), "no find by context->handle");
939
940 for (auto storage = storageIdToPathMap.begin(); storage != storageIdToPathMap.end(); ++storage) {
941 if (it->second.compare(0, storage->second.size(), storage->second) == 0) {
942 context->storageID = storage->first;
943 return;
944 }
945 }
946 }
947
GetObjectPropList(const std::shared_ptr<MtpOperationContext> & context,std::shared_ptr<std::vector<Property>> & outProps)948 int32_t MtpMediaLibrary::GetObjectPropList(const std::shared_ptr<MtpOperationContext> &context,
949 std::shared_ptr<std::vector<Property>> &outProps)
950 {
951 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_INVALID_OBJECTHANDLE, "context is nullptr");
952 if (context->property == 0) {
953 CHECK_AND_RETURN_RET_LOG(context->groupCode != 0, MTP_ERROR_PARAMETER_NOT_SUPPORTED, "groupCode error");
954 MEDIA_ERR_LOG("context property = 0");
955 return MTP_ERROR_SPECIFICATION_BY_GROUP_UNSUPPORTED;
956 }
957 if (context->depth == MTP_ALL_DEPTH && (context->handle == 0 || context->handle == MTP_ALL_HANDLE_ID)) {
958 context->handle = MTP_ALL_HANDLE_ID;
959 context->depth = 0;
960 }
961 MEDIA_DEBUG_LOG("GetObjectPropList handle[0x%{public}x], depth[0x%{public}x] parent[%{public}d]",
962 context->handle, context->depth, context->parent);
963 bool cond = (context->depth == 0 || context->depth == 1);
964 CHECK_AND_RETURN_RET_LOG(cond, MTP_ERROR_SPECIFICATION_BY_DEPTH_UNSUPPORTED, "depth error");
965
966 MEDIA_DEBUG_LOG("GetObjectPropList storageID[%{public}d],format[%{public}d],property[0x%{public}x]",
967 context->storageID, context->format, context->property);
968 int32_t errCode = MTP_ERROR_INVALID_OBJECTHANDLE;
969 {
970 WriteLock lock(g_mutex);
971 CorrectStorageId(context);
972 auto handlesMap = GetHandlesMap(context);
973 bool condition = (handlesMap == nullptr || handlesMap->empty());
974 CHECK_AND_RETURN_RET_LOG(!condition, errCode, "MtpMediaLibrary::GetObjectPropList out is empty");
975 errCode = MtpDataUtils::GetMtpPropList(handlesMap, pathToHandleMap, context, outProps);
976 }
977 return errCode;
978 }
979
AddPathToMap(const std::string & path)980 uint32_t MtpMediaLibrary::AddPathToMap(const std::string &path)
981 {
982 uint32_t id;
983 auto it = pathToHandleMap.find(path);
984 if (it == pathToHandleMap.end()) {
985 id = GetId();
986 AddToHandlePathMap(path, id);
987 } else {
988 id = it->second;
989 }
990 MEDIA_DEBUG_LOG("MtpMediaLibrary::AddPathToMap path[%{public}s] id[%{public}d]", path.c_str(), id);
991 return id;
992 }
993
ScanDirWithType(const std::string & root,std::shared_ptr<std::unordered_map<uint32_t,std::string>> & out)994 uint32_t MtpMediaLibrary::ScanDirWithType(const std::string &root,
995 std::shared_ptr<std::unordered_map<uint32_t, std::string>> &out)
996 {
997 MEDIA_INFO_LOG("MtpMediaLibrary::ScanDirWithType root[%{public}s]", root.c_str());
998 CHECK_AND_RETURN_RET_LOG(out != nullptr, E_ERR, "out is nullptr");
999 CHECK_AND_RETURN_RET_LOG(access(root.c_str(), R_OK) == 0, E_ERR, "access failed root[%{public}s]", root.c_str());
1000 std::error_code ec;
1001 if (sf::exists(root, ec) && sf::is_directory(root, ec)) {
1002 if (!IsRootPath(root)) {
1003 out->emplace(AddPathToMap(root), root);
1004 }
1005 for (const auto& entry : sf::directory_iterator(root, ec)) {
1006 if (ec.value() != MTP_SUCCESS) {
1007 continue;
1008 }
1009 if (sf::is_directory(entry.path(), ec) && IsHiddenDirectory(entry.path().string())) {
1010 continue;
1011 }
1012 out->emplace(AddPathToMap(entry.path().string()), entry.path().string());
1013 }
1014 } else if (sf::exists(root, ec) && sf::is_regular_file(root, ec)) {
1015 out->emplace(AddPathToMap(root), root);
1016 }
1017 return MTP_SUCCESS;
1018 }
1019
ScanDirTraverseWithType(const std::string & root,std::shared_ptr<std::unordered_map<uint32_t,std::string>> & out)1020 uint32_t MtpMediaLibrary::ScanDirTraverseWithType(const std::string &root,
1021 std::shared_ptr<std::unordered_map<uint32_t, std::string>> &out)
1022 {
1023 MEDIA_INFO_LOG("MtpMediaLibrary::ScanDirTraverseWithType root[%{public}s]", root.c_str());
1024 CHECK_AND_RETURN_RET_LOG(out != nullptr, E_ERR, "out is nullptr");
1025 CHECK_AND_RETURN_RET_LOG(access(root.c_str(), R_OK) == 0, E_ERR, "access failed root[%{public}s]", root.c_str());
1026 std::error_code ec;
1027 if (sf::exists(root, ec) && sf::is_directory(root, ec)) {
1028 if (!IsRootPath(root)) {
1029 out->emplace(AddPathToMap(root), root);
1030 }
1031 for (const auto& entry : sf::recursive_directory_iterator(root, ec)) {
1032 if (ec.value() != MTP_SUCCESS) {
1033 continue;
1034 }
1035 if (sf::is_directory(entry.path(), ec) && IsHiddenDirectory(entry.path().string())) {
1036 continue;
1037 }
1038 out->emplace(AddPathToMap(entry.path().string()), entry.path().string());
1039 }
1040 } else if (sf::exists(root, ec) && sf::is_regular_file(root, ec)) {
1041 out->emplace(AddPathToMap(root), root);
1042 }
1043 return MTP_SUCCESS;
1044 }
1045
GetObjectPropValue(const std::shared_ptr<MtpOperationContext> & context,uint64_t & outIntVal,uint128_t & outLongVal,std::string & outStrVal)1046 int32_t MtpMediaLibrary::GetObjectPropValue(const std::shared_ptr<MtpOperationContext> &context,
1047 uint64_t &outIntVal, uint128_t &outLongVal, std::string &outStrVal)
1048 {
1049 CHECK_AND_RETURN_RET_LOG(context != nullptr, MTP_ERROR_INVALID_OBJECTHANDLE, "context is nullptr");
1050 MEDIA_INFO_LOG("MtpMediaLibrary::GetObjectPropValue handle[%{public}d] property[%{public}d]",
1051 context->handle, context->property);
1052 std::string path("");
1053 CHECK_AND_RETURN_RET_LOG(GetPathById(context->handle, path) == MTP_SUCCESS, MTP_ERROR_INVALID_OBJECTHANDLE,
1054 "MtpMediaLibrary::GetObjectPropValue handle not found");
1055
1056 if (MTP_PROPERTY_PARENT_OBJECT_CODE == context->property) {
1057 outIntVal = GetParentId(path);
1058 return MTP_SUCCESS;
1059 }
1060
1061 PropertyValue propValue;
1062 int32_t errCode = MtpDataUtils::GetMtpPropValue(path, context->property, 0, propValue);
1063 CHECK_AND_RETURN_RET_LOG(errCode == MTP_SUCCESS, MTP_ERROR_INVALID_OBJECTHANDLE, "fail to get GetMtpPropValue");
1064 outIntVal = propValue.outIntVal;
1065 outStrVal = propValue.outStrVal;
1066 return errCode;
1067 }
1068
TryAddExternalStorage(const std::string & fsUuid,uint32_t & storageId)1069 bool MtpMediaLibrary::TryAddExternalStorage(const std::string &fsUuid, uint32_t &storageId)
1070 {
1071 MEDIA_DEBUG_LOG("TryAddExternalStorage fsUuid[%{public}s]", fsUuid.c_str());
1072 CHECK_AND_RETURN_RET_LOG(!fsUuid.empty(), false, "fsUuid is empty");
1073 {
1074 WriteLock lock(g_mutex);
1075 return AddExternalStorage(fsUuid, storageId);
1076 }
1077 }
1078
TryRemoveExternalStorage(const std::string & fsUuid,uint32_t & storageId)1079 bool MtpMediaLibrary::TryRemoveExternalStorage(const std::string &fsUuid, uint32_t &storageId)
1080 {
1081 MEDIA_DEBUG_LOG("TryRemoveExternalStorage fsUuid[%{public}s]", fsUuid.c_str());
1082 CHECK_AND_RETURN_RET_LOG(!fsUuid.empty(), false, "fsUuid is empty");
1083 const std::string path = GetExternalPathByUuid(fsUuid);
1084 storageId = 0;
1085 {
1086 WriteLock lock(g_mutex);
1087 for (const auto &it : storageIdToPathMap) {
1088 if (path.compare(it.second) == 0) {
1089 storageId = it.first;
1090 storageIdToPathMap.erase(storageId);
1091 break;
1092 }
1093 }
1094 CHECK_AND_RETURN_RET_LOG(storageId != 0, false, "external storage is not exists");
1095 ErasePathInfoSub(path);
1096 }
1097 auto manager = MtpStorageManager::GetInstance();
1098 CHECK_AND_RETURN_RET_LOG(manager != nullptr, false, "MtpStorageManager instance is nullptr");
1099 auto storage = manager->GetStorage(storageId);
1100 if (storage != nullptr) {
1101 manager->RemoveStorage(storage);
1102 }
1103 return true;
1104 }
1105
GetExternalPathByUuid(const std::string & fsUuid)1106 const std::string MtpMediaLibrary::GetExternalPathByUuid(const std::string &fsUuid)
1107 {
1108 return std::string(SD_DOC + "/" + fsUuid);
1109 }
1110
AddExternalStorage(const std::string & fsUuid,uint32_t & storageId)1111 bool MtpMediaLibrary::AddExternalStorage(const std::string &fsUuid, uint32_t &storageId)
1112 {
1113 CHECK_AND_RETURN_RET_LOG(!fsUuid.empty(), false, "fsUuid is empty");
1114 const std::string path = GetExternalPathByUuid(fsUuid);
1115 for (const auto &it : storageIdToPathMap) {
1116 if (path.compare(it.second) == 0) {
1117 storageId = it.first;
1118 return true;
1119 }
1120 }
1121 uint32_t id = SD_START_ID;
1122 for (id = SD_START_ID; id <= SD_END_ID; id++) {
1123 if (storageIdToPathMap.find(id) == storageIdToPathMap.end()) {
1124 break;
1125 }
1126 }
1127 CHECK_AND_RETURN_RET_LOG(id <= SD_END_ID, false, "error: too many ext disk");
1128 MEDIA_INFO_LOG("Mtp AddExternalStorage id[%{public}d] path[%{public}s]", id, path.c_str());
1129
1130 auto manager = MtpStorageManager::GetInstance();
1131 CHECK_AND_RETURN_RET_LOG(manager != nullptr, false, "MtpStorageManager instance is nullptr");
1132
1133 auto storage = make_shared<Storage>();
1134 CHECK_AND_RETURN_RET_LOG(storage != nullptr, false, "storage is nullptr");
1135 storage->SetStorageID(id);
1136 storage->SetStorageType(MTP_STORAGE_REMOVABLERAM);
1137 storage->SetFilesystemType(MTP_FILESYSTEM_GENERICHIERARCHICAL);
1138 storage->SetAccessCapability(MTP_ACCESS_READ_WRITE);
1139 storage->SetMaxCapacity(manager->GetTotalSize(path));
1140 storage->SetFreeSpaceInBytes(manager->GetFreeSize(path));
1141 storage->SetFreeSpaceInObjects(0);
1142 std::string desc = manager->GetStorageDescription(MTP_STORAGE_REMOVABLERAM);
1143 id > SD_START_ID ? desc.append(" (").append(std::to_string(id - INNER_STORAGE_ID)).append(")") : desc;
1144 storage->SetStorageDescription(desc);
1145 storage->SetVolumeIdentifier(fsUuid);
1146 manager->AddStorage(storage);
1147 storageIdToPathMap[id] = path;
1148 storageId = id;
1149 MEDIA_ERR_LOG("Mtp AddExternalStorage storageId[%{public}d] path[%{public}s]", id, path.c_str());
1150 return true;
1151 }
1152
GetStorageIds()1153 int MtpMediaLibrary::GetStorageIds()
1154 {
1155 auto manager = MtpStorageManager::GetInstance();
1156 CHECK_AND_RETURN_RET_LOG(manager != nullptr, E_ERR, "MtpStorageManager instance is nullptr");
1157
1158 auto storage = make_shared<Storage>();
1159 CHECK_AND_RETURN_RET_LOG(storage != nullptr, E_ERR, "storage is nullptr");
1160 storage->SetStorageID(INNER_STORAGE_ID);
1161 storage->SetStorageType(MTP_STORAGE_FIXEDRAM);
1162 storage->SetFilesystemType(MTP_FILESYSTEM_GENERICHIERARCHICAL);
1163 storage->SetAccessCapability(MTP_ACCESS_READ_WRITE);
1164 storage->SetMaxCapacity(manager->GetTotalSize(PUBLIC_DOC));
1165 storage->SetFreeSpaceInBytes(manager->GetFreeSize(PUBLIC_DOC));
1166 storage->SetFreeSpaceInObjects(0);
1167 storage->SetStorageDescription(manager->GetStorageDescription(MTP_STORAGE_FIXEDRAM));
1168 manager->AddStorage(storage);
1169 {
1170 WriteLock lock(g_mutex);
1171 storageIdToPathMap[INNER_STORAGE_ID] = PUBLIC_DOC;
1172 GetExternalStorages();
1173 }
1174 return MTP_SUCCESS;
1175 }
1176
GetExternalStorages()1177 void MtpMediaLibrary::GetExternalStorages()
1178 {
1179 CHECK_AND_RETURN_LOG(access(SD_DOC.c_str(), R_OK) == 0, "access failed [%{public}s]", SD_DOC.c_str());
1180 std::error_code ec;
1181 CHECK_AND_RETURN_LOG(sf::exists(SD_DOC, ec) && sf::is_directory(SD_DOC, ec), "SD_DOC is not exists");
1182 for (const auto& entry : sf::directory_iterator(SD_DOC, ec)) {
1183 if (!sf::is_directory(entry.path(), ec)) {
1184 continue;
1185 }
1186 MEDIA_INFO_LOG("Mtp GetExternalStorages path[%{public}s]", entry.path().c_str());
1187
1188 uint32_t storageId;
1189 AddExternalStorage(entry.path().filename().string(), storageId);
1190 }
1191 }
1192
ErasePathInfo(const uint32_t handle,const std::string & path)1193 void MtpMediaLibrary::ErasePathInfo(const uint32_t handle, const std::string &path)
1194 {
1195 CHECK_AND_RETURN_LOG(!path.empty(), "path is empty");
1196 if (handleToPathMap.find(handle) != handleToPathMap.end()) {
1197 handleToPathMap.erase(handle);
1198 }
1199 if (pathToHandleMap.find(path) != pathToHandleMap.end()) {
1200 pathToHandleMap.erase(path);
1201 }
1202
1203 ErasePathInfoSub(path);
1204 }
1205
ErasePathInfoSub(const std::string & path)1206 void MtpMediaLibrary::ErasePathInfoSub(const std::string &path)
1207 {
1208 std::string prefix = path + PATH_SEPARATOR;
1209 const auto size = prefix.size();
1210 std::vector<std::string> erasePaths;
1211 for (const auto &it : pathToHandleMap) {
1212 if (prefix.compare(it.first.substr(0, size)) != 0) {
1213 continue;
1214 }
1215 erasePaths.push_back(std::move(it.first));
1216 if (handleToPathMap.find(it.second) != handleToPathMap.end()) {
1217 handleToPathMap.erase(it.second);
1218 }
1219 }
1220 for (const auto &p : erasePaths) {
1221 if (pathToHandleMap.find(p) != pathToHandleMap.end()) {
1222 pathToHandleMap.erase(p);
1223 }
1224 }
1225 std::vector<std::string>().swap(erasePaths);
1226 }
1227
1228 } // namespace Media
1229 } // namespace OHOS
1230