• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "media_asset_change_request_impl.h"
17 
18 #include <fcntl.h>
19 #include <sys/sendfile.h>
20 #include "securec.h"
21 
22 #include "oh_media_asset.h"
23 #include "media_log.h"
24 #include "medialibrary_errno.h"
25 #include "media_file_utils.h"
26 #include "media_column.h"
27 #include "file_uri.h"
28 #include "directory_ex.h"
29 #include "medialibrary_db_const.h"
30 #include "access_token.h"
31 #include "accesstoken_kit.h"
32 #include "ipc_skeleton.h"
33 #include "image_packer.h"
34 #include "permission_utils.h"
35 #include "media_userfile_client.h"
36 #include "userfilemgr_uri.h"
37 
38 using namespace std;
39 using namespace OHOS::Media;
40 using namespace OHOS::Security::AccessToken;
41 
42 atomic<uint32_t> MediaAssetChangeRequestImpl::cacheFileId_(0);
43 const string MOVING_PHOTO_VIDEO_EXTENSION = "mp4";
44 const string API_VERSION = "api_version";
45 
CreateMediaAssetChangeRequest(std::shared_ptr<MediaAsset> mediaAsset)46 std::shared_ptr<MediaAssetChangeRequest> MediaAssetChangeRequestFactory::CreateMediaAssetChangeRequest(
47     std::shared_ptr<MediaAsset> mediaAsset)
48 {
49     std::shared_ptr<MediaAssetChangeRequestImpl> impl = std::make_shared<MediaAssetChangeRequestImpl>(mediaAsset);
50     CHECK_AND_PRINT_LOG(impl != nullptr, "Failed to create MediaAssetChangeRequestImpl instance.");
51 
52     return impl;
53 }
54 
MediaAssetChangeRequestImpl(std::shared_ptr<MediaAsset> mediaAsset)55 MediaAssetChangeRequestImpl::MediaAssetChangeRequestImpl(std::shared_ptr<MediaAsset> mediaAsset)
56 {
57     mediaAsset_ = mediaAsset;
58     movingPhotoVideoDataBuffer_ = nullptr;
59     dataBuffer_ = nullptr;
60     movingPhotoVideoResourceMode_ = AddResourceMode::DEFAULT;
61     addResourceMode_ = AddResourceMode::DEFAULT;
62     movingPhotoVideoBufferSize_ = 0;
63     dataBufferSize_ = 0;
64 }
65 
~MediaAssetChangeRequestImpl()66 MediaAssetChangeRequestImpl::~MediaAssetChangeRequestImpl()
67 {
68     mediaAsset_ = nullptr;
69     if (movingPhotoVideoDataBuffer_ != nullptr) {
70         delete[] movingPhotoVideoDataBuffer_;
71         movingPhotoVideoDataBuffer_ = nullptr;
72     }
73 
74     if (dataBuffer_ != nullptr) {
75         delete[] dataBuffer_;
76         dataBuffer_ = nullptr;
77     }
78 
79     addResourceTypes_.clear();
80     assetChangeOperations_.clear();
81 }
82 
GetWriteCacheHandler(int32_t * fd)83 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::GetWriteCacheHandler(int32_t* fd)
84 {
85     unique_lock<mutex> ulock(mutex_);
86     auto fileAsset = mediaAsset_->GetFileAssetInstance();
87     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR, "fileAsset get failed!");
88     CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "cann't be moving photo!");
89     CHECK_AND_RETURN_RET_LOG(CheckWriteOperation(MediaLibrary_ResourceType::MEDIA_LIBRARY_VIDEO_RESOURCE),
90         MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "Not supported!");
91 
92     int32_t ret = OpenWriteCacheHandler();
93     CHECK_AND_RETURN_RET_LOG(ret >= 0,
94         MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "Failed to open write cache handler,ret: %{public}d", ret);
95 
96     *fd = ret;
97     RecordChangeOperation(AssetChangeOperation::GET_WRITE_CACHE_HANDLER);
98     return MEDIA_LIBRARY_OK;
99 }
100 
SaveCameraPhoto(MediaLibrary_ImageFileType imageFileType)101 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::SaveCameraPhoto(MediaLibrary_ImageFileType imageFileType)
102 {
103     unique_lock<mutex> ulock(mutex_);
104     auto fileAsset = mediaAsset_->GetFileAssetInstance();
105     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
106 
107     MediaType mediaType = fileAsset->GetMediaType();
108     if ((mediaType == MEDIA_TYPE_IMAGE && imageFileType == MEDIA_LIBRARY_IMAGE_JPEG) ||
109         (mediaType == MEDIA_TYPE_VIDEO && imageFileType == MEDIA_LIBRARY_FILE_VIDEO)) {
110         RecordChangeOperation(AssetChangeOperation::SAVE_CAMERA_PHOTO);
111         return MEDIA_LIBRARY_OK;
112     }
113     MEDIA_ERR_LOG("type mismatch, mediaType: %{public}d, imageFileType: %{public}d", mediaType, imageFileType);
114     return MEDIA_LIBRARY_PARAMETER_ERROR;
115 }
116 
DiscardCameraPhoto()117 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::DiscardCameraPhoto()
118 {
119     unique_lock<mutex> ulock(mutex_);
120     auto fileAsset = mediaAsset_->GetFileAssetInstance();
121     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
122 
123     RecordChangeOperation(AssetChangeOperation::DISCARD_CAMERA_PHOTO);
124     return MEDIA_LIBRARY_OK;
125 }
126 
AddResourceWithUri(MediaLibrary_ResourceType resourceType,char * fileUri)127 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::AddResourceWithUri(MediaLibrary_ResourceType resourceType,
128     char* fileUri)
129 {
130     unique_lock<mutex> ulock(mutex_);
131     CHECK_AND_RETURN_RET_LOG(CheckWriteOperation(resourceType), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
132         "operation not support");
133 
134     string realPath;
135     OHOS::AppFileService::ModuleFileUri::FileUri fileUriStr(fileUri);
136     string path = fileUriStr.GetRealPath();
137     bool result = OHOS::PathToRealPath(path, realPath);
138     CHECK_AND_RETURN_RET_LOG(result, MEDIA_LIBRARY_NO_SUCH_FILE, "File real path isn't existed");
139 
140     auto fileAsset = mediaAsset_->GetFileAssetInstance();
141     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
142     CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
143         "not support edit moving photo with uri");
144 
145     CHECK_AND_RETURN_RET_LOG(fileAsset->GetMediaType() == MediaFileUtils::GetMediaType(realPath),
146         MEDIA_LIBRARY_PARAMETER_ERROR, "Invalid file type");
147 
148     realPath_ = realPath;
149     addResourceMode_ = AddResourceMode::FILE_URI;
150     RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
151     addResourceTypes_.push_back(resourceType);
152     return MEDIA_LIBRARY_OK;
153 }
154 
AddResourceWithBuffer(MediaLibrary_ResourceType resourceType,uint8_t * buffer,uint32_t length)155 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::AddResourceWithBuffer(MediaLibrary_ResourceType resourceType,
156     uint8_t* buffer, uint32_t length)
157 {
158     unique_lock<mutex> ulock(mutex_);
159     CHECK_AND_RETURN_RET_LOG(CheckWriteOperation(resourceType), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
160         "operation not support");
161 
162     auto fileAsset = mediaAsset_->GetFileAssetInstance();
163     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
164     CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
165         "not support edit moving photo with buffer");
166 
167     if (dataBuffer_ != nullptr) {
168         delete[] dataBuffer_;
169     }
170     dataBuffer_ = new uint8_t[length + 1];
171     CHECK_AND_RETURN_RET_LOG(dataBuffer_ != nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR,
172         "create dataBuffer_ failed!");
173 
174     dataBufferSize_ = length;
175     if (length > 0) {
176         int ret = memcpy_s(dataBuffer_, length + 1, buffer, length);
177         CHECK_AND_RETURN_RET_LOG(ret == E_OK, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR,
178             "memcpy buffer failed!");
179     }
180     addResourceMode_ = AddResourceMode::DATA_BUFFER;
181     RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
182     addResourceTypes_.push_back(resourceType);
183     return MEDIA_LIBRARY_OK;
184 }
185 
ApplyChanges()186 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::ApplyChanges()
187 {
188     unique_lock<mutex> ulock(mutex_);
189     bool result = CheckChangeOperations();
190     CHECK_AND_RETURN_RET_LOG(result, MEDIA_LIBRARY_PARAMETER_ERROR, "Failed to check asset change request operations");
191 
192     auto fileAsset = mediaAsset_->GetFileAssetInstance();
193     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR, "fileAsset is nullptr");
194 
195     unordered_set<AssetChangeOperation> appliedOperations;
196     for (const auto& changeOperation : assetChangeOperations_) {
197         if (appliedOperations.find(changeOperation) != appliedOperations.end()) {
198             continue;
199         }
200 
201         bool valid = ChangeOperationExecute(changeOperation);
202         CHECK_AND_RETURN_RET_LOG(valid, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
203             "Failed to apply asset change request, operation: %{public}d", changeOperation);
204 
205         appliedOperations.insert(changeOperation);
206     }
207     assetChangeOperations_.clear();
208     addResourceTypes_.clear();
209     movingPhotoVideoResourceMode_ = AddResourceMode::DEFAULT;
210     addResourceMode_ = AddResourceMode::DEFAULT;
211     return MEDIA_LIBRARY_OK;
212 }
213 
IsMovingPhoto()214 bool MediaAssetChangeRequestImpl::IsMovingPhoto()
215 {
216     auto fileAsset = mediaAsset_->GetFileAssetInstance();
217     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is nullptr");
218 
219     return fileAsset->GetPhotoSubType() == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO);
220 }
221 
CheckWriteOperation(MediaLibrary_ResourceType resourceType)222 bool MediaAssetChangeRequestImpl::CheckWriteOperation(MediaLibrary_ResourceType resourceType)
223 {
224     if (Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER) ||
225         Contains(AssetChangeOperation::ADD_RESOURCE)) {
226         MEDIA_ERR_LOG("The previous asset creation/modification request has not been applied");
227         return false;
228     }
229     return true;
230 }
231 
ContainsResource(MediaLibrary_ResourceType resourceType)232 bool MediaAssetChangeRequestImpl::ContainsResource(MediaLibrary_ResourceType resourceType)
233 {
234     return find(addResourceTypes_.begin(), addResourceTypes_.end(), resourceType) != addResourceTypes_.end();
235 }
236 
Contains(AssetChangeOperation changeOperation)237 bool MediaAssetChangeRequestImpl::Contains(AssetChangeOperation changeOperation)
238 {
239     return find(assetChangeOperations_.begin(), assetChangeOperations_.end(), changeOperation) !=
240            assetChangeOperations_.end();
241 }
242 
OpenWriteCacheHandler(bool isMovingPhotoVideo)243 int32_t MediaAssetChangeRequestImpl::OpenWriteCacheHandler(bool isMovingPhotoVideo)
244 {
245     auto fileAsset = mediaAsset_->GetFileAssetInstance();
246     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
247 
248     // specify mp4 extension for cache file of moving photo video
249     string extension = isMovingPhotoVideo ? MOVING_PHOTO_VIDEO_EXTENSION
250         : MediaFileUtils::GetExtensionFromPath(fileAsset->GetDisplayName());
251     int64_t currentTimestamp = MediaFileUtils::UTCTimeNanoSeconds();
252     uint32_t cacheFileId = FetchAddCacheFileId();
253     string cacheFileName = to_string(currentTimestamp) + "_" + to_string(cacheFileId) + "." + extension;
254     string uri = PhotoColumn::PHOTO_CACHE_URI_PREFIX + cacheFileName;
255     MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
256     Uri openCacheUri(uri);
257     int32_t ret = UserFileClient::OpenFile(openCacheUri, MEDIA_FILEMODE_WRITEONLY);
258     CHECK_AND_RETURN_RET_LOG(ret != E_PERMISSION_DENIED, ret, "Open cache file failed, permission denied");
259     CHECK_AND_PRINT_LOG(ret >= 0, "Open cache file failed, ret: %{public}d", ret);
260 
261     if (isMovingPhotoVideo) {
262         cacheMovingPhotoVideoName_ = cacheFileName;
263     } else {
264         cacheFileName_ = cacheFileName;
265     }
266     return ret;
267 }
268 
FetchAddCacheFileId()269 uint32_t MediaAssetChangeRequestImpl::FetchAddCacheFileId()
270 {
271     return cacheFileId_.fetch_add(1);
272 }
273 
RecordChangeOperation(AssetChangeOperation changeOperation)274 void MediaAssetChangeRequestImpl::RecordChangeOperation(AssetChangeOperation changeOperation)
275 {
276     assetChangeOperations_.push_back(changeOperation);
277 }
278 
CheckChangeOperations()279 bool MediaAssetChangeRequestImpl::CheckChangeOperations()
280 {
281     CHECK_AND_RETURN_RET_LOG(assetChangeOperations_.size() != 0, false, "None request to apply");
282 
283     auto fileAsset = mediaAsset_->GetFileAssetInstance();
284     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is null");
285     CHECK_AND_RETURN_RET_LOG(fileAsset->GetId() > 0, false, "Invalid asset change request");
286 
287     return true;
288 }
289 
ChangeOperationExecute(AssetChangeOperation option)290 bool MediaAssetChangeRequestImpl::ChangeOperationExecute(AssetChangeOperation option)
291 {
292     bool ret = false;
293     switch (option) {
294         case AssetChangeOperation::GET_WRITE_CACHE_HANDLER:
295             ret = SubmitCacheExecute();
296             break;
297         case AssetChangeOperation::ADD_RESOURCE:
298             ret = AddResourceExecute();
299             break;
300         case AssetChangeOperation::SAVE_CAMERA_PHOTO:
301             ret = SaveCameraPhotoExecute();
302             break;
303         case AssetChangeOperation::DISCARD_CAMERA_PHOTO:
304             ret = DiscardCameraPhotoExecute();
305             break;
306         default:
307             break;
308     }
309     return ret;
310 }
311 
SubmitCacheExecute()312 bool MediaAssetChangeRequestImpl::SubmitCacheExecute()
313 {
314     int32_t ret = SubmitCache();
315     CHECK_AND_RETURN_RET_LOG(ret >= 0, false, "Failed to write cache, ret: %{public}d", ret);
316 
317     return true;
318 }
319 
AddResourceExecute()320 bool MediaAssetChangeRequestImpl::AddResourceExecute()
321 {
322     CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), false, "not support edit moving photo with buffer or uri");
323 
324     if (!HasWritePermission()) {
325         return WriteBySecurityComponent();
326     }
327 
328     int32_t cacheFd = OpenWriteCacheHandler();
329     CHECK_AND_RETURN_RET_LOG(cacheFd >= 0, false, "Failed to open write cache handler, err: %{public}d", cacheFd);
330 
331     OHOS::UniqueFd uniqueFd(cacheFd);
332     AddResourceMode mode = addResourceMode_;
333     CHECK_AND_RETURN_RET_LOG(AddResourceByMode(uniqueFd, mode), false, "Faild to write cache file");
334 
335     return SubmitCacheExecute();
336 }
337 
SaveCameraPhotoExecute()338 bool MediaAssetChangeRequestImpl::SaveCameraPhotoExecute()
339 {
340     bool containsAddResource = find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
341         AssetChangeOperation::ADD_RESOURCE) != assetChangeOperations_.end();
342     std::string uriStr = PAH_SAVE_CAMERA_PHOTO;
343     if (containsAddResource && !PermissionUtils::IsSystemApp()) {
344         // remove high quality photo
345         MEDIA_INFO_LOG("discard high quality photo because add resource by third app");
346         DiscardHighQualityPhoto();
347 
348         // set dirty flag when third-party hap calling addResource to save camera photo
349         MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::PHOTO_DIRTY,
350             to_string(static_cast<int32_t>(DirtyType::TYPE_NEW)));
351     }
352 
353     // The watermark will trigger the scan. If the watermark is turned on, there is no need to trigger the scan again.
354     bool needScan = std::find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
355         AssetChangeOperation::ADD_FILTERS) == assetChangeOperations_.end();
356 
357     auto fileAsset = mediaAsset_->GetFileAssetInstance();
358     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is nullptr");
359 
360     MediaFileUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
361     MediaFileUtils::UriAppendKeyValue(uriStr, MEDIA_OPERN_KEYWORD, to_string(needScan));
362     MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_FILE_PATH, fileAsset->GetUri());
363     MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_ID, to_string(fileAsset->GetId()));
364     MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::PHOTO_SUBTYPE,
365         to_string(fileAsset->GetPhotoSubType()));
366     Uri uri(uriStr);
367     OHOS::DataShare::DataShareValuesBucket valuesBucket;
368     valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, false);
369     OHOS::DataShare::DataSharePredicates predicates;
370     int32_t changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
371     CHECK_AND_RETURN_RET_LOG(changedRows >= 0, false, "save camera photo fail, err: %{public}d", changedRows);
372 
373     return true;
374 }
375 
DiscardCameraPhotoExecute()376 bool MediaAssetChangeRequestImpl::DiscardCameraPhotoExecute()
377 {
378     OHOS::DataShare::DataSharePredicates predicates;
379     OHOS::DataShare::DataShareValuesBucket valuesBucket;
380     valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, true);
381 
382     auto fileAsset = mediaAsset_->GetFileAssetInstance();
383     predicates.EqualTo(PhotoColumn::MEDIA_ID, to_string(fileAsset->GetId()));
384 
385     string uri = PAH_DISCARD_CAMERA_PHOTO;
386     MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
387     Uri updateAssetUri(uri);
388     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
389     CHECK_AND_RETURN_RET_LOG(changedRows >= 0, false,
390         "Failed to update property of asset, err: %{public}d", changedRows);
391     return true;
392 }
393 
HasWritePermission()394 bool MediaAssetChangeRequestImpl::HasWritePermission()
395 {
396     AccessTokenID tokenCaller = OHOS::IPCSkeleton::GetSelfTokenID();
397     int result = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_WRITE_IMAGEVIDEO);
398     return result == PermissionState::PERMISSION_GRANTED;
399 }
400 
WriteBySecurityComponent()401 bool MediaAssetChangeRequestImpl::WriteBySecurityComponent()
402 {
403     int32_t ret = CopyToMediaLibrary(addResourceMode_);
404     CHECK_AND_RETURN_RET_LOG(ret >= 0, false,
405         "Failed to write by security component, ret: %{public}d", ret);
406 
407     return true;
408 }
409 
CopyToMediaLibrary(AddResourceMode mode)410 int32_t MediaAssetChangeRequestImpl::CopyToMediaLibrary(AddResourceMode mode)
411 {
412     auto fileAsset = mediaAsset_->GetFileAssetInstance();
413     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
414 
415     int32_t ret = E_ERR;
416     string assetUri = fileAsset->GetUri();
417     CHECK_AND_RETURN_RET_LOG(!assetUri.empty(), E_ERR, "Failed to check empty asset uri");
418     CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), E_ERR, "not support edit moving photo with buffer or uri");
419 
420     Uri uri(assetUri);
421     OHOS::UniqueFd destFd(UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY));
422     CHECK_AND_RETURN_RET_LOG(destFd.Get() >= 0, destFd.Get(),
423         "Failed to open %{public}s with error: %{public}d", assetUri.c_str(), destFd.Get());
424 
425     if (mode == AddResourceMode::FILE_URI) {
426         ret = CopyFileToMediaLibrary(destFd);
427     } else if (mode == AddResourceMode::DATA_BUFFER) {
428         ret = CopyDataBufferToMediaLibrary(destFd);
429     } else {
430         MEDIA_ERR_LOG("Invalid mode: %{public}d", mode);
431         return E_INVALID_VALUES;
432     }
433 
434     return ret;
435 }
436 
CopyFileToMediaLibrary(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)437 int32_t MediaAssetChangeRequestImpl::CopyFileToMediaLibrary(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
438 {
439     string srcRealPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
440     CHECK_AND_RETURN_RET_LOG(!srcRealPath.empty(), E_FAIL, "Failed to check real path of source");
441 
442     string absFilePath;
443     CHECK_AND_RETURN_RET_LOG(OHOS::PathToRealPath(srcRealPath, absFilePath), E_FAIL, "Not real path %{public}s",
444         srcRealPath.c_str());
445 
446     OHOS::UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
447     CHECK_AND_RETURN_RET_LOG(srcFd.Get() >= 0, srcFd.Get(),
448         "Failed to open %{public}s, errno=%{public}d", absFilePath.c_str(), errno);
449 
450     int32_t err = SendFile(srcFd, destFd);
451     CHECK_AND_PRINT_LOG(err == E_OK, "Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
452 
453     return err;
454 }
455 
CopyDataBufferToMediaLibrary(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)456 int32_t MediaAssetChangeRequestImpl::CopyDataBufferToMediaLibrary(const OHOS::UniqueFd& destFd,
457     bool isMovingPhotoVideo)
458 {
459     size_t offset = 0;
460     size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
461     void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
462     while (offset < length) {
463         ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
464         CHECK_AND_RETURN_RET_LOG(written >= 0, written,
465             "Failed to copy data buffer, return %{public}d", static_cast<int>(written));
466 
467         offset += static_cast<size_t>(written);
468     }
469     return E_OK;
470 }
471 
SendToCacheFile(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)472 bool MediaAssetChangeRequestImpl::SendToCacheFile(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
473 {
474     string realPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
475     string absFilePath;
476     CHECK_AND_RETURN_RET_LOG(OHOS::PathToRealPath(realPath, absFilePath), false,
477         "Not real path %{public}s, errno=%{public}d", realPath.c_str(), errno);
478 
479     OHOS::UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
480     CHECK_AND_RETURN_RET_LOG(srcFd.Get() >= 0, false, "Failed to open file, errno=%{public}d", errno);
481 
482     int32_t err = SendFile(srcFd, destFd);
483     CHECK_AND_RETURN_RET_LOG(err == E_OK, false,
484         "Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
485 
486     return true;
487 }
488 
SubmitCache()489 int32_t MediaAssetChangeRequestImpl::SubmitCache()
490 {
491     auto fileAsset = mediaAsset_->GetFileAssetInstance();
492     CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
493     CHECK_AND_RETURN_RET_LOG(!cacheFileName_.empty() || !cacheMovingPhotoVideoName_.empty(), E_FAIL,
494         "Failed to check cache file");
495 
496     string uri = PAH_SUBMIT_CACHE;
497     MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
498     Uri submitCacheUri(uri);
499     OHOS::DataShare::DataShareValuesBucket valuesBucket;
500     valuesBucket.Put(PhotoColumn::MEDIA_ID, fileAsset->GetId());
501     valuesBucket.Put(CACHE_FILE_NAME, cacheFileName_);
502     int32_t ret = UserFileClient::Insert(submitCacheUri, valuesBucket);
503 
504     cacheFileName_.clear();
505     cacheMovingPhotoVideoName_.clear();
506     return ret;
507 }
508 
SendFile(const OHOS::UniqueFd & srcFd,const OHOS::UniqueFd & destFd)509 int32_t MediaAssetChangeRequestImpl::SendFile(const OHOS::UniqueFd& srcFd, const OHOS::UniqueFd& destFd)
510 {
511     CHECK_AND_RETURN_RET_LOG((srcFd.Get() >= 0 && destFd.Get() >= 0), E_ERR,
512         "Failed to check srcFd: %{public}d and destFd: %{public}d", srcFd.Get(), destFd.Get());
513 
514     struct stat statSrc {};
515     int32_t status = fstat(srcFd.Get(), &statSrc);
516     CHECK_AND_RETURN_RET_LOG(status == 0, status, "Failed to get file stat, errno=%{public}d", errno);
517 
518     off_t offset = 0;
519     off_t fileSize = statSrc.st_size;
520     while (offset < fileSize) {
521         ssize_t sent = sendfile(destFd.Get(), srcFd.Get(), &offset, fileSize - offset);
522         CHECK_AND_RETURN_RET_LOG(sent >= 0, sent,
523             "Failed to sendfile with errno=%{public}d, srcFd=%{public}d, destFd=%{public}d",
524             errno, srcFd.Get(), destFd.Get());
525     }
526 
527     return E_OK;
528 }
529 
AddResourceByMode(const OHOS::UniqueFd & uniqueFd,AddResourceMode mode,bool isMovingPhotoVideo)530 bool MediaAssetChangeRequestImpl::AddResourceByMode(const OHOS::UniqueFd& uniqueFd,
531     AddResourceMode mode, bool isMovingPhotoVideo)
532 {
533     bool isWriteSuccess = false;
534     if (mode == AddResourceMode::DATA_BUFFER) {
535         isWriteSuccess = WriteCacheByArrayBuffer(uniqueFd, isMovingPhotoVideo);
536     } else if (mode == AddResourceMode::FILE_URI) {
537         isWriteSuccess = SendToCacheFile(uniqueFd, isMovingPhotoVideo);
538     } else {
539         MEDIA_ERR_LOG("Unsupported addResource mode");
540     }
541     return isWriteSuccess;
542 }
543 
WriteCacheByArrayBuffer(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)544 bool MediaAssetChangeRequestImpl::WriteCacheByArrayBuffer(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
545 {
546     size_t offset = 0;
547     size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
548     void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
549     while (offset < length) {
550         ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
551         CHECK_AND_RETURN_RET_LOG(written >= 0, false,
552             "Failed to write data buffer to cache file, return %{public}d", static_cast<int>(written));
553 
554         offset += static_cast<size_t>(written);
555     }
556     return true;
557 }
558 
DiscardHighQualityPhoto()559 void MediaAssetChangeRequestImpl::DiscardHighQualityPhoto()
560 {
561     string uriStr = PAH_REMOVE_MSC_TASK;
562     MediaFileUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
563     Uri uri(uriStr);
564     OHOS::DataShare::DataSharePredicates predicates;
565     int errCode = 0;
566 
567     auto fileAsset = mediaAsset_->GetFileAssetInstance();
568     vector<string> columns { to_string(fileAsset->GetId()) };
569     UserFileClient::Query(uri, predicates, columns, errCode);
570 }
571