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