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