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