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