• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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