1 /*
2 * Copyright (C) 2023 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 #include "command/recv_command_v10.h"
16
17 #include <cerrno>
18 #include <fcntl.h>
19 #include <set>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include "constant.h"
25 #include "datashare_result_set.h"
26 #include "datashare_predicates.h"
27 #include "directory_ex.h"
28 #include "media_file_uri.h"
29 #include "media_file_utils.h"
30 #include "media_log.h"
31 #include "medialibrary_errno.h"
32 #include "mediatool_uri.h"
33 #include "utils/mediatool_command_utils.h"
34 #include "userfile_client.h"
35 #include "userfile_client_ex.h"
36
37 namespace OHOS {
38 namespace Media {
39 namespace MediaTool {
40
41 using namespace std;
42
43 constexpr mode_t OPEN_MODE = 0644;
44
GetWriteFilePath(const ExecEnv & env,const string & displayName,std::string & wFilePath)45 static bool GetWriteFilePath(const ExecEnv& env, const string& displayName, std::string& wFilePath)
46 {
47 wFilePath = env.recvParam.recvPath;
48 if (!MediaFileUtils::IsDirectory(wFilePath)) {
49 if (env.recvParam.isRecvAll) {
50 MEDIA_ERR_LOG("RecvFilePath:%{public}s is not a directory.", wFilePath.c_str());
51 printf("RecvFilePath:%s is not a directory.\n", wFilePath.c_str());
52 return false;
53 }
54 } else {
55 wFilePath = IncludeTrailingPathDelimiter(wFilePath);
56 if (displayName.empty()) {
57 MEDIA_ERR_LOG("RecvFile displayName is null.");
58 printf("RecvFile displayName is null.\n");
59 return false;
60 }
61 wFilePath += displayName;
62 }
63 return true;
64 }
65
RecvFile(const ExecEnv & env,const FileAsset & fileAsset,bool isRecvMovingPhotoVideo=false)66 static int32_t RecvFile(const ExecEnv &env, const FileAsset &fileAsset, bool isRecvMovingPhotoVideo = false)
67 {
68 std::string wFilePath;
69 string displayName = fileAsset.GetDisplayName();
70 if (isRecvMovingPhotoVideo) {
71 string title = fileAsset.GetTitle();
72 displayName = title + ".mp4";
73 }
74 if (!GetWriteFilePath(env, displayName, wFilePath)) {
75 return Media::E_ERR;
76 }
77 auto wfd = open(wFilePath.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, OPEN_MODE);
78 if (wfd <= 0) {
79 MEDIA_ERR_LOG("Open write path failed. errno:%{public}d, path name:%{public}s", errno, wFilePath.c_str());
80 printf("%s open write path failed. errno:%d, path name:%s\n", STR_FAIL.c_str(), errno, wFilePath.c_str());
81 return Media::E_ERR;
82 }
83
84 std::string openUri = fileAsset.GetUri();
85 if (isRecvMovingPhotoVideo) {
86 MediaFileUtils::UriAppendKeyValue(openUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD,
87 OPEN_MOVING_PHOTO_VIDEO);
88 }
89 auto rfd = UserFileClientEx::Open(openUri, Media::MEDIA_FILEMODE_READONLY);
90 if (rfd <= 0) {
91 MEDIA_ERR_LOG("Open source media file failed. uri:%{public}s", openUri.c_str());
92 printf("%s open source media file failed.\n", STR_FAIL.c_str());
93 close(wfd);
94 return Media::E_ERR;
95 }
96 auto ret = MediaFileUtils::CopyFile(rfd, wfd);
97 if (!ret) {
98 MEDIA_ERR_LOG("Receive data failed. uri: %{public}s", openUri.c_str());
99 printf("%s receive data failed.\n", STR_FAIL.c_str());
100 } else {
101 printf("%s\n", wFilePath.c_str());
102 }
103 UserFileClientEx::Close(fileAsset.GetUri(), rfd, Media::MEDIA_FILEMODE_READONLY);
104 close(wfd);
105 return ret ? Media::E_OK : Media::E_ERR;
106 }
107
IsRoot()108 static bool IsRoot()
109 {
110 constexpr int rootUid = 0;
111 return getuid() == rootUid;
112 }
113
ConvertToCloudPath(const string & inputPath)114 static string ConvertToCloudPath(const string& inputPath)
115 {
116 std::string tmpPath = inputPath;
117 const std::string localPrefix = "/storage/media/local/files/Photo";
118 const std::string cloudPrefix = "/storage/cloud/files/Photo";
119
120 // Checks if input path starts with /storage/media/local/files/Photo
121 if (tmpPath.rfind(localPrefix, 0) == 0) {
122 tmpPath.replace(0, localPrefix.length(), cloudPrefix);
123 } else {
124 MEDIA_ERR_LOG("Convert to cloud path failed, input path format incorrect");
125 return tmpPath;
126 }
127
128 return tmpPath;
129 }
130
QueryAssets(std::shared_ptr<DataShare::DataShareResultSet> & resultSet,const std::string & tableName)131 int32_t RecvCommandV10::QueryAssets(std::shared_ptr<DataShare::DataShareResultSet>& resultSet,
132 const std::string& tableName)
133 {
134 if (!UserFileClientEx::CheckTableName(tableName)) {
135 MEDIA_ERR_LOG("tableName %{public}s is Invalid", tableName.c_str());
136 return Media::E_ERR;
137 }
138 resultSet = nullptr;
139 std::string queryUriStr = UserFileClientEx::GetQueryUri(tableName);
140 if (queryUriStr.empty()) {
141 MEDIA_ERR_LOG("query failed. queryUriStr:empty, tableName:%{public}s", tableName.c_str());
142 return Media::E_ERR;
143 }
144
145 OHOS::DataShare::DataSharePredicates predicates;
146 if (!isRecvAll_) {
147 if (!uri_.empty()) {
148 MediaFileUri fileUri(uri_);
149 std::string id = fileUri.GetFileId();
150 predicates.EqualTo(MediaColumn::MEDIA_ID, id);
151 } else if (!srcPath_.empty()) {
152 predicates.EqualTo(MediaColumn::MEDIA_FILE_PATH, ConvertToCloudPath(srcPath_));
153 }
154 }
155
156 Uri queryUri(queryUriStr);
157 if (!IsRoot() && tableName == PhotoColumn::PHOTOS_TABLE) {
158 predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, 0);
159 }
160 std::vector<std::string> columns;
161 int errCode = 0;
162 MEDIA_INFO_LOG("query. queryUri: %{public}s, tableName: %{public}s, uri: %{public}s, "
163 "path: %{public}s", queryUri.ToString().c_str(), tableName.c_str(), uri_.c_str(), srcPath_.c_str());
164 resultSet = UserFileClient::Query(queryUri, predicates, columns, errCode);
165 if (resultSet == nullptr) {
166 MEDIA_ERR_LOG("query failed. resultSet:null, errCode:%{public}d.", errCode);
167 return ((errCode == Media::E_OK) ? Media::E_OK : Media::E_ERR);
168 }
169 if (errCode != Media::E_OK) {
170 MEDIA_ERR_LOG("query failed. errCode:%{public}d.", errCode);
171 resultSet->Close();
172 return Media::E_ERR;
173 }
174 return Media::E_OK;
175 }
176
QueryMovingPhotoAsset(const string & filePath,unique_ptr<FileAsset> & movingPhotoAsset)177 bool RecvCommandV10::QueryMovingPhotoAsset(const string& filePath, unique_ptr<FileAsset>& movingPhotoAsset)
178 {
179 std::string queryUriStr = UserFileClientEx::GetQueryUri(tableName_);
180 if (queryUriStr.empty()) {
181 MEDIA_ERR_LOG("query failed. queryUriStr:empty, tableName:%{public}s", tableName_.c_str());
182 return false;
183 }
184
185 string queryPath = ConvertToCloudPath(filePath);
186 string::size_type lastDotPos = queryPath.find_last_of('.');
187 if (lastDotPos == string::npos) {
188 MEDIA_ERR_LOG("filePath does not have an extension: %{public}s", filePath.c_str());
189 return false;
190 }
191 string pathPrefix = queryPath.substr(0, lastDotPos + 1);
192
193 OHOS::DataShare::DataSharePredicates predicates;
194 predicates.Like(MediaColumn::MEDIA_FILE_PATH, pathPrefix + "%");
195 predicates.And()->EqualTo(PhotoColumn::PHOTO_SUBTYPE, static_cast<int32_t>(PhotoSubType::MOVING_PHOTO));
196 if (!IsRoot()) {
197 predicates.And()->EqualTo(MediaColumn::MEDIA_HIDDEN, 0);
198 }
199
200 Uri queryUri(queryUriStr);
201 std::vector<std::string> columns;
202 int errCode = 0;
203 auto resultSet = UserFileClient::Query(queryUri, predicates, columns, errCode);
204 if (resultSet == nullptr) {
205 MEDIA_ERR_LOG("query failed. resultSet:null, errCode:%{public}d.", errCode);
206 return false;
207 }
208 if (errCode != Media::E_OK) {
209 MEDIA_ERR_LOG("query failed. errCode:%{public}d.", errCode);
210 resultSet->Close();
211 return false;
212 }
213 std::shared_ptr<FetchResult<FileAsset>> fetchResult = std::make_shared<FetchResult<FileAsset>>(resultSet);
214 fetchResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
215 auto count = fetchResult->GetCount();
216 if (count <= 0) {
217 return false;
218 }
219 movingPhotoAsset = fetchResult->GetFirstObject();
220
221 return true;
222 }
223
IsMovingPhotoVideoPath(unique_ptr<FileAsset> & movingPhotoAsset)224 bool RecvCommandV10::IsMovingPhotoVideoPath(unique_ptr<FileAsset>& movingPhotoAsset)
225 {
226 if (srcPath_.empty()) {
227 return false;
228 }
229
230 string extension = MediaFileUtils::GetExtensionFromPath(srcPath_);
231 if (!MediaFileUtils::CheckMovingPhotoVideoExtension(extension)) {
232 return false;
233 }
234
235 if (QueryMovingPhotoAsset(srcPath_, movingPhotoAsset)) {
236 return true;
237 }
238 return false;
239 }
240
PathExists(const string & path)241 static bool PathExists(const string& path)
242 {
243 std::string lsUriStr = TOOL_LS_PHOTO;
244 Uri lsUri(lsUriStr);
245 DataShare::DataShareValuesBucket values;
246 values.Put(MediaColumn::MEDIA_FILE_PATH, path);
247 string outString;
248 UserFileClient::InsertExt(lsUri, values, outString);
249 return !outString.empty();
250 }
251
RecvAssets(const ExecEnv & env,const std::string & tableName)252 int32_t RecvCommandV10::RecvAssets(const ExecEnv& env, const std::string& tableName)
253 {
254 printf("Table Name: %s\n", tableName.c_str());
255 if (!srcPath_.empty() && !PathExists(srcPath_)) {
256 MEDIA_ERR_LOG("Path does not exist, path: %{public}s",
257 srcPath_.c_str());
258 printf("%s This path does not refer to a valid media asset \n",
259 STR_FAIL.c_str());
260 return Media::E_ERR;
261 }
262 std::shared_ptr<DataShare::DataShareResultSet> resultSet;
263 auto res = QueryAssets(resultSet, tableName);
264 std::shared_ptr<FetchResult<FileAsset>> fetchResult = std::make_shared<FetchResult<FileAsset>>(resultSet);
265 fetchResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
266 if (res != Media::E_OK) {
267 MEDIA_ERR_LOG("query issue. tableName:%{public}s", tableName.c_str());
268 printf("%s query issue. tableName:%s\n", STR_FAIL.c_str(), tableName.c_str());
269 return Media::E_ERR;
270 }
271 if (fetchResult == nullptr) {
272 return Media::E_ERR;
273 }
274 auto count = fetchResult->GetCount();
275 if (count == 0 && !isRecvAll_) {
276 unique_ptr<FileAsset> movingPhotoAsset;
277 if (IsMovingPhotoVideoPath(movingPhotoAsset)) {
278 RecvFile(env, *movingPhotoAsset, true);
279 return E_OK;
280 }
281 MEDIA_ERR_LOG("No valid media asset found. uri: %{public}s, path: %{public}s",
282 uri_.c_str(), srcPath_.c_str());
283 printf("%s This %s does not refer to a valid media asset \n",
284 STR_FAIL.c_str(), srcPath_.empty() ? "uri" : "path");
285 return Media::E_ERR;
286 }
287 for (int32_t index = 0; index < count; index++) {
288 auto fileAsset = fetchResult->GetObjectAtPosition(index);
289 RecvFile(env, *fileAsset);
290 }
291 fetchResult->Close();
292 return Media::E_OK;
293 }
294
CheckArgs(const ExecEnv & env)295 bool RecvCommandV10::CheckArgs(const ExecEnv& env)
296 {
297 isRecvAll_ = env.recvParam.isRecvAll;
298 if (isRecvAll_) {
299 return true;
300 }
301
302 string recvTarget = env.recvParam.recvTarget;
303 string reformattedPath;
304 if (MediatoolCommandUtils::CheckAndReformatPathParam(recvTarget, reformattedPath)) {
305 inputPath_ = recvTarget;
306 srcPath_ = reformattedPath;
307 tableName_ = PhotoColumn::PHOTOS_TABLE;
308 return true;
309 }
310
311 MediaFileUri fileUri(recvTarget);
312 if (fileUri.IsValid()) {
313 uri_ = recvTarget;
314 tableName_ = UserFileClientEx::GetTableNameByUri(uri_);
315 if (tableName_.empty()) {
316 MEDIA_ERR_LOG("Failed to get table name from uri. uri: %{public}s", uri_.c_str());
317 printf("%s uri issue. uri: %s\n", STR_FAIL.c_str(), uri_.c_str());
318 return false;
319 }
320 return true;
321 }
322
323 return false;
324 }
325
Start(const ExecEnv & env)326 int32_t RecvCommandV10::Start(const ExecEnv &env)
327 {
328 if (!CheckArgs(env)) {
329 MEDIA_ERR_LOG("recv target invalid: %{public}s", env.recvParam.recvTarget.c_str());
330 printf("%s recv target invalid: %s\n", STR_FAIL.c_str(), env.recvParam.recvTarget.c_str());
331 return Media::E_ERR;
332 }
333 if (isRecvAll_) {
334 bool hasError = false;
335 auto tables = UserFileClientEx::GetSupportTables();
336 for (auto tableName : tables) {
337 if (RecvAssets(env, tableName) != Media::E_OK) {
338 hasError = true;
339 }
340 printf("\n");
341 }
342 return hasError ? Media::E_ERR : Media::E_OK;
343 } else {
344 return RecvAssets(env, tableName_);
345 }
346 }
347
348 } // namespace MediaTool
349 } // namespace Media
350 } // namespace OHOS
351