• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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