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 CHECK_AND_RETURN_RET_LOG(imageFileType == MEDIA_LIBRARY_IMAGE_JPEG, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
104 "imageFileType not support");
105
106 unique_lock<mutex> ulock(mutex_);
107 auto fileAsset = mediaAsset_->GetFileAssetInstance();
108 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
109
110 RecordChangeOperation(AssetChangeOperation::SAVE_CAMERA_PHOTO);
111 return MEDIA_LIBRARY_OK;
112 }
113
DiscardCameraPhoto()114 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::DiscardCameraPhoto()
115 {
116 unique_lock<mutex> ulock(mutex_);
117 auto fileAsset = mediaAsset_->GetFileAssetInstance();
118 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
119
120 RecordChangeOperation(AssetChangeOperation::DISCARD_CAMERA_PHOTO);
121 return MEDIA_LIBRARY_OK;
122 }
123
AddResourceWithUri(MediaLibrary_ResourceType resourceType,char * fileUri)124 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::AddResourceWithUri(MediaLibrary_ResourceType resourceType,
125 char* fileUri)
126 {
127 unique_lock<mutex> ulock(mutex_);
128 CHECK_AND_RETURN_RET_LOG(CheckWriteOperation(resourceType), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
129 "operation not support");
130
131 string realPath;
132 OHOS::AppFileService::ModuleFileUri::FileUri fileUriStr(fileUri);
133 string path = fileUriStr.GetRealPath();
134 bool result = OHOS::PathToRealPath(path, realPath);
135 CHECK_AND_RETURN_RET_LOG(result, MEDIA_LIBRARY_NO_SUCH_FILE, "File real path isn't existed");
136
137 auto fileAsset = mediaAsset_->GetFileAssetInstance();
138 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
139 CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
140 "not support edit moving photo with uri");
141
142 CHECK_AND_RETURN_RET_LOG(fileAsset->GetMediaType() == MediaFileUtils::GetMediaType(realPath),
143 MEDIA_LIBRARY_PARAMETER_ERROR, "Invalid file type");
144
145 realPath_ = realPath;
146 addResourceMode_ = AddResourceMode::FILE_URI;
147 RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
148 addResourceTypes_.push_back(resourceType);
149 return MEDIA_LIBRARY_OK;
150 }
151
AddResourceWithBuffer(MediaLibrary_ResourceType resourceType,uint8_t * buffer,uint32_t length)152 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::AddResourceWithBuffer(MediaLibrary_ResourceType resourceType,
153 uint8_t* buffer, uint32_t length)
154 {
155 unique_lock<mutex> ulock(mutex_);
156 CHECK_AND_RETURN_RET_LOG(CheckWriteOperation(resourceType), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
157 "operation not support");
158
159 auto fileAsset = mediaAsset_->GetFileAssetInstance();
160 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
161 CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
162 "not support edit moving photo with buffer");
163
164 if (dataBuffer_ != nullptr) {
165 delete[] dataBuffer_;
166 }
167 dataBuffer_ = new uint8_t[length + 1];
168 CHECK_AND_RETURN_RET_LOG(dataBuffer_ != nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR,
169 "create dataBuffer_ failed!");
170
171 dataBufferSize_ = length;
172 if (length > 0) {
173 int ret = memcpy_s(dataBuffer_, length + 1, buffer, length);
174 CHECK_AND_RETURN_RET_LOG(ret == E_OK, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR,
175 "memcpy buffer failed!");
176 }
177 addResourceMode_ = AddResourceMode::DATA_BUFFER;
178 RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
179 addResourceTypes_.push_back(resourceType);
180 return MEDIA_LIBRARY_OK;
181 }
182
ApplyChanges()183 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::ApplyChanges()
184 {
185 unique_lock<mutex> ulock(mutex_);
186 bool result = CheckChangeOperations();
187 CHECK_AND_RETURN_RET_LOG(result, MEDIA_LIBRARY_PARAMETER_ERROR, "Failed to check asset change request operations");
188
189 auto fileAsset = mediaAsset_->GetFileAssetInstance();
190 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR, "fileAsset is nullptr");
191
192 unordered_set<AssetChangeOperation> appliedOperations;
193 for (const auto& changeOperation : assetChangeOperations_) {
194 if (appliedOperations.find(changeOperation) != appliedOperations.end()) {
195 continue;
196 }
197
198 bool valid = ChangeOperationExecute(changeOperation);
199 CHECK_AND_RETURN_RET_LOG(valid, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
200 "Failed to apply asset change request, operation: %{public}d", changeOperation);
201
202 appliedOperations.insert(changeOperation);
203 }
204 assetChangeOperations_.clear();
205 addResourceTypes_.clear();
206 movingPhotoVideoResourceMode_ = AddResourceMode::DEFAULT;
207 addResourceMode_ = AddResourceMode::DEFAULT;
208 return MEDIA_LIBRARY_OK;
209 }
210
IsMovingPhoto()211 bool MediaAssetChangeRequestImpl::IsMovingPhoto()
212 {
213 auto fileAsset = mediaAsset_->GetFileAssetInstance();
214 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is nullptr");
215
216 return fileAsset->GetPhotoSubType() == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO);
217 }
218
CheckWriteOperation(MediaLibrary_ResourceType resourceType)219 bool MediaAssetChangeRequestImpl::CheckWriteOperation(MediaLibrary_ResourceType resourceType)
220 {
221 if (Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER) ||
222 Contains(AssetChangeOperation::ADD_RESOURCE)) {
223 MEDIA_ERR_LOG("The previous asset creation/modification request has not been applied");
224 return false;
225 }
226 return true;
227 }
228
ContainsResource(MediaLibrary_ResourceType resourceType)229 bool MediaAssetChangeRequestImpl::ContainsResource(MediaLibrary_ResourceType resourceType)
230 {
231 return find(addResourceTypes_.begin(), addResourceTypes_.end(), resourceType) != addResourceTypes_.end();
232 }
233
Contains(AssetChangeOperation changeOperation)234 bool MediaAssetChangeRequestImpl::Contains(AssetChangeOperation changeOperation)
235 {
236 return find(assetChangeOperations_.begin(), assetChangeOperations_.end(), changeOperation) !=
237 assetChangeOperations_.end();
238 }
239
OpenWriteCacheHandler(bool isMovingPhotoVideo)240 int32_t MediaAssetChangeRequestImpl::OpenWriteCacheHandler(bool isMovingPhotoVideo)
241 {
242 auto fileAsset = mediaAsset_->GetFileAssetInstance();
243 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
244
245 // specify mp4 extension for cache file of moving photo video
246 string extension = isMovingPhotoVideo ? MOVING_PHOTO_VIDEO_EXTENSION
247 : MediaFileUtils::GetExtensionFromPath(fileAsset->GetDisplayName());
248 int64_t currentTimestamp = MediaFileUtils::UTCTimeNanoSeconds();
249 uint32_t cacheFileId = FetchAddCacheFileId();
250 string cacheFileName = to_string(currentTimestamp) + "_" + to_string(cacheFileId) + "." + extension;
251 string uri = PhotoColumn::PHOTO_CACHE_URI_PREFIX + cacheFileName;
252 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
253 Uri openCacheUri(uri);
254 int32_t ret = UserFileClient::OpenFile(openCacheUri, MEDIA_FILEMODE_WRITEONLY);
255 CHECK_AND_RETURN_RET_LOG(ret != E_PERMISSION_DENIED, ret, "Open cache file failed, permission denied");
256 CHECK_AND_PRINT_LOG(ret >= 0, "Open cache file failed, ret: %{public}d", ret);
257
258 if (isMovingPhotoVideo) {
259 cacheMovingPhotoVideoName_ = cacheFileName;
260 } else {
261 cacheFileName_ = cacheFileName;
262 }
263 return ret;
264 }
265
FetchAddCacheFileId()266 uint32_t MediaAssetChangeRequestImpl::FetchAddCacheFileId()
267 {
268 return cacheFileId_.fetch_add(1);
269 }
270
RecordChangeOperation(AssetChangeOperation changeOperation)271 void MediaAssetChangeRequestImpl::RecordChangeOperation(AssetChangeOperation changeOperation)
272 {
273 assetChangeOperations_.push_back(changeOperation);
274 }
275
CheckChangeOperations()276 bool MediaAssetChangeRequestImpl::CheckChangeOperations()
277 {
278 CHECK_AND_RETURN_RET_LOG(assetChangeOperations_.size() != 0, false, "None request to apply");
279
280 auto fileAsset = mediaAsset_->GetFileAssetInstance();
281 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is null");
282 CHECK_AND_RETURN_RET_LOG(fileAsset->GetId() > 0, false, "Invalid asset change request");
283
284 return true;
285 }
286
ChangeOperationExecute(AssetChangeOperation option)287 bool MediaAssetChangeRequestImpl::ChangeOperationExecute(AssetChangeOperation option)
288 {
289 bool ret = false;
290 switch (option) {
291 case AssetChangeOperation::GET_WRITE_CACHE_HANDLER:
292 ret = SubmitCacheExecute();
293 break;
294 case AssetChangeOperation::ADD_RESOURCE:
295 ret = AddResourceExecute();
296 break;
297 case AssetChangeOperation::SAVE_CAMERA_PHOTO:
298 ret = SaveCameraPhotoExecute();
299 break;
300 case AssetChangeOperation::DISCARD_CAMERA_PHOTO:
301 ret = DiscardCameraPhotoExecute();
302 break;
303 default:
304 break;
305 }
306 return ret;
307 }
308
SubmitCacheExecute()309 bool MediaAssetChangeRequestImpl::SubmitCacheExecute()
310 {
311 int32_t ret = SubmitCache();
312 CHECK_AND_RETURN_RET_LOG(ret >= 0, false, "Failed to write cache, ret: %{public}d", ret);
313
314 return true;
315 }
316
AddResourceExecute()317 bool MediaAssetChangeRequestImpl::AddResourceExecute()
318 {
319 CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), false, "not support edit moving photo with buffer or uri");
320
321 if (!HasWritePermission()) {
322 return WriteBySecurityComponent();
323 }
324
325 int32_t cacheFd = OpenWriteCacheHandler();
326 CHECK_AND_RETURN_RET_LOG(cacheFd >= 0, false, "Failed to open write cache handler, err: %{public}d", cacheFd);
327
328 OHOS::UniqueFd uniqueFd(cacheFd);
329 AddResourceMode mode = addResourceMode_;
330 CHECK_AND_RETURN_RET_LOG(AddResourceByMode(uniqueFd, mode), false, "Faild to write cache file");
331
332 return SubmitCacheExecute();
333 }
334
SaveCameraPhotoExecute()335 bool MediaAssetChangeRequestImpl::SaveCameraPhotoExecute()
336 {
337 bool containsAddResource = find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
338 AssetChangeOperation::ADD_RESOURCE) != assetChangeOperations_.end();
339 std::string uriStr = PAH_SAVE_CAMERA_PHOTO;
340 if (containsAddResource && !PermissionUtils::IsSystemApp()) {
341 // remove high quality photo
342 MEDIA_INFO_LOG("discard high quality photo because add resource by third app");
343 DiscardHighQualityPhoto();
344
345 // set dirty flag when third-party hap calling addResource to save camera photo
346 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::PHOTO_DIRTY,
347 to_string(static_cast<int32_t>(DirtyType::TYPE_NEW)));
348 }
349
350 // The watermark will trigger the scan. If the watermark is turned on, there is no need to trigger the scan again.
351 bool needScan = std::find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
352 AssetChangeOperation::ADD_FILTERS) == assetChangeOperations_.end();
353
354 auto fileAsset = mediaAsset_->GetFileAssetInstance();
355 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is nullptr");
356
357 MediaFileUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
358 MediaFileUtils::UriAppendKeyValue(uriStr, MEDIA_OPERN_KEYWORD, to_string(needScan));
359 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_FILE_PATH, fileAsset->GetUri());
360 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_ID, to_string(fileAsset->GetId()));
361 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::PHOTO_SUBTYPE,
362 to_string(fileAsset->GetPhotoSubType()));
363 Uri uri(uriStr);
364 OHOS::DataShare::DataShareValuesBucket valuesBucket;
365 valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, false);
366 OHOS::DataShare::DataSharePredicates predicates;
367 bool ret = UserFileClient::Update(uri, predicates, valuesBucket);
368 CHECK_AND_RETURN_RET_LOG(ret, false, "save camera photo fail");
369
370 return true;
371 }
372
DiscardCameraPhotoExecute()373 bool MediaAssetChangeRequestImpl::DiscardCameraPhotoExecute()
374 {
375 OHOS::DataShare::DataSharePredicates predicates;
376 OHOS::DataShare::DataShareValuesBucket valuesBucket;
377 valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, true);
378
379 auto fileAsset = mediaAsset_->GetFileAssetInstance();
380 predicates.EqualTo(PhotoColumn::MEDIA_ID, to_string(fileAsset->GetId()));
381
382 string uri = PAH_DISCARD_CAMERA_PHOTO;
383 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
384 Uri updateAssetUri(uri);
385 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
386 CHECK_AND_RETURN_RET_LOG(changedRows >= 0, false,
387 "Failed to update property of asset, err: %{public}d", changedRows);
388 return true;
389 }
390
HasWritePermission()391 bool MediaAssetChangeRequestImpl::HasWritePermission()
392 {
393 AccessTokenID tokenCaller = OHOS::IPCSkeleton::GetSelfTokenID();
394 int result = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_WRITE_IMAGEVIDEO);
395 return result == PermissionState::PERMISSION_GRANTED;
396 }
397
WriteBySecurityComponent()398 bool MediaAssetChangeRequestImpl::WriteBySecurityComponent()
399 {
400 int32_t ret = CopyToMediaLibrary(addResourceMode_);
401 CHECK_AND_RETURN_RET_LOG(ret >= 0, false,
402 "Failed to write by security component, ret: %{public}d", ret);
403
404 return true;
405 }
406
CopyToMediaLibrary(AddResourceMode mode)407 int32_t MediaAssetChangeRequestImpl::CopyToMediaLibrary(AddResourceMode mode)
408 {
409 auto fileAsset = mediaAsset_->GetFileAssetInstance();
410 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
411
412 int32_t ret = E_ERR;
413 string assetUri = fileAsset->GetUri();
414 CHECK_AND_RETURN_RET_LOG(!assetUri.empty(), E_ERR, "Failed to check empty asset uri");
415 CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), E_ERR, "not support edit moving photo with buffer or uri");
416
417 Uri uri(assetUri);
418 OHOS::UniqueFd destFd(UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY));
419 CHECK_AND_RETURN_RET_LOG(destFd.Get() >= 0, destFd.Get(),
420 "Failed to open %{public}s with error: %{public}d", assetUri.c_str(), destFd.Get());
421
422 if (mode == AddResourceMode::FILE_URI) {
423 ret = CopyFileToMediaLibrary(destFd);
424 } else if (mode == AddResourceMode::DATA_BUFFER) {
425 ret = CopyDataBufferToMediaLibrary(destFd);
426 } else {
427 MEDIA_ERR_LOG("Invalid mode: %{public}d", mode);
428 return E_INVALID_VALUES;
429 }
430
431 return ret;
432 }
433
CopyFileToMediaLibrary(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)434 int32_t MediaAssetChangeRequestImpl::CopyFileToMediaLibrary(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
435 {
436 string srcRealPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
437 CHECK_AND_RETURN_RET_LOG(!srcRealPath.empty(), E_FAIL, "Failed to check real path of source");
438
439 string absFilePath;
440 CHECK_AND_RETURN_RET_LOG(OHOS::PathToRealPath(srcRealPath, absFilePath), E_FAIL, "Not real path %{public}s",
441 srcRealPath.c_str());
442
443 OHOS::UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
444 CHECK_AND_RETURN_RET_LOG(srcFd.Get() >= 0, srcFd.Get(),
445 "Failed to open %{public}s, errno=%{public}d", absFilePath.c_str(), errno);
446
447 int32_t err = SendFile(srcFd, destFd);
448 CHECK_AND_PRINT_LOG(err == E_OK, "Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
449
450 return err;
451 }
452
CopyDataBufferToMediaLibrary(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)453 int32_t MediaAssetChangeRequestImpl::CopyDataBufferToMediaLibrary(const OHOS::UniqueFd& destFd,
454 bool isMovingPhotoVideo)
455 {
456 size_t offset = 0;
457 size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
458 void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
459 while (offset < length) {
460 ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
461 CHECK_AND_RETURN_RET_LOG(written >= 0, written,
462 "Failed to copy data buffer, return %{public}d", static_cast<int>(written));
463
464 offset += static_cast<size_t>(written);
465 }
466 return E_OK;
467 }
468
SendToCacheFile(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)469 bool MediaAssetChangeRequestImpl::SendToCacheFile(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
470 {
471 string realPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
472 string absFilePath;
473 CHECK_AND_RETURN_RET_LOG(OHOS::PathToRealPath(realPath, absFilePath), false,
474 "Not real path %{public}s, errno=%{public}d", realPath.c_str(), errno);
475
476 OHOS::UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
477 CHECK_AND_RETURN_RET_LOG(srcFd.Get() >= 0, false, "Failed to open file, errno=%{public}d", errno);
478
479 int32_t err = SendFile(srcFd, destFd);
480 CHECK_AND_RETURN_RET_LOG(err == E_OK, false,
481 "Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
482
483 return true;
484 }
485
SubmitCache()486 int32_t MediaAssetChangeRequestImpl::SubmitCache()
487 {
488 auto fileAsset = mediaAsset_->GetFileAssetInstance();
489 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
490 CHECK_AND_RETURN_RET_LOG(!cacheFileName_.empty() || !cacheMovingPhotoVideoName_.empty(), E_FAIL,
491 "Failed to check cache file");
492
493 string uri = PAH_SUBMIT_CACHE;
494 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
495 Uri submitCacheUri(uri);
496 OHOS::DataShare::DataShareValuesBucket valuesBucket;
497 valuesBucket.Put(PhotoColumn::MEDIA_ID, fileAsset->GetId());
498 valuesBucket.Put(CACHE_FILE_NAME, cacheFileName_);
499 int32_t ret = UserFileClient::Insert(submitCacheUri, valuesBucket);
500
501 cacheFileName_.clear();
502 cacheMovingPhotoVideoName_.clear();
503 return ret;
504 }
505
SendFile(const OHOS::UniqueFd & srcFd,const OHOS::UniqueFd & destFd)506 int32_t MediaAssetChangeRequestImpl::SendFile(const OHOS::UniqueFd& srcFd, const OHOS::UniqueFd& destFd)
507 {
508 CHECK_AND_RETURN_RET_LOG((srcFd.Get() >= 0 && destFd.Get() >= 0), E_ERR,
509 "Failed to check srcFd: %{public}d and destFd: %{public}d", srcFd.Get(), destFd.Get());
510
511 struct stat statSrc {};
512 int32_t status = fstat(srcFd.Get(), &statSrc);
513 CHECK_AND_RETURN_RET_LOG(status == 0, status, "Failed to get file stat, errno=%{public}d", errno);
514
515 off_t offset = 0;
516 off_t fileSize = statSrc.st_size;
517 while (offset < fileSize) {
518 ssize_t sent = sendfile(destFd.Get(), srcFd.Get(), &offset, fileSize - offset);
519 CHECK_AND_RETURN_RET_LOG(sent >= 0, sent,
520 "Failed to sendfile with errno=%{public}d, srcFd=%{public}d, destFd=%{public}d",
521 errno, srcFd.Get(), destFd.Get());
522 }
523
524 return E_OK;
525 }
526
AddResourceByMode(const OHOS::UniqueFd & uniqueFd,AddResourceMode mode,bool isMovingPhotoVideo)527 bool MediaAssetChangeRequestImpl::AddResourceByMode(const OHOS::UniqueFd& uniqueFd,
528 AddResourceMode mode, bool isMovingPhotoVideo)
529 {
530 bool isWriteSuccess = false;
531 if (mode == AddResourceMode::DATA_BUFFER) {
532 isWriteSuccess = WriteCacheByArrayBuffer(uniqueFd, isMovingPhotoVideo);
533 } else if (mode == AddResourceMode::FILE_URI) {
534 isWriteSuccess = SendToCacheFile(uniqueFd, isMovingPhotoVideo);
535 } else {
536 MEDIA_ERR_LOG("Unsupported addResource mode");
537 }
538 return isWriteSuccess;
539 }
540
WriteCacheByArrayBuffer(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)541 bool MediaAssetChangeRequestImpl::WriteCacheByArrayBuffer(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
542 {
543 size_t offset = 0;
544 size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
545 void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
546 while (offset < length) {
547 ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
548 CHECK_AND_RETURN_RET_LOG(written >= 0, false,
549 "Failed to write data buffer to cache file, return %{public}d", static_cast<int>(written));
550
551 offset += static_cast<size_t>(written);
552 }
553 return true;
554 }
555
DiscardHighQualityPhoto()556 void MediaAssetChangeRequestImpl::DiscardHighQualityPhoto()
557 {
558 string uriStr = PAH_REMOVE_MSC_TASK;
559 MediaFileUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
560 Uri uri(uriStr);
561 OHOS::DataShare::DataSharePredicates predicates;
562 int errCode = 0;
563
564 auto fileAsset = mediaAsset_->GetFileAssetInstance();
565 vector<string> columns { to_string(fileAsset->GetId()) };
566 UserFileClient::Query(uri, predicates, columns, errCode);
567 }
568