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