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/send_command_v10.h"
16
17 #include <chrono>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <thread>
22 #include <unistd.h>
23
24 #include "constant.h"
25 #include "directory_ex.h"
26 #include "exec_env.h"
27 #include "media_file_uri.h"
28 #include "media_file_utils.h"
29 #include "medialibrary_errno.h"
30 #include "medialibrary_napi_utils.h"
31 #include "userfile_client_ex.h"
32
33 namespace OHOS {
34 namespace Media {
35 namespace MediaTool {
36 static constexpr int32_t SLEEP_NOTIFY_TIME = 2000;
37
38 struct FileInfo {
39 Media::MediaType mediaType {Media::MediaType::MEDIA_TYPE_DEFAULT};
40 std::string displayName;
41 std::string path;
42 std::string uri;
43 int32_t id {-1};
44 bool toBeRemove {false};
45 int32_t result {-1};
ToStrOHOS::Media::MediaTool::FileInfo46 [[nodiscard]] std::string ToStr() const
47 {
48 std::string str;
49 str.append("mediaType:");
50 str.append(std::to_string(static_cast<uint32_t>(mediaType)));
51 str.append(", displayName:");
52 str.append(displayName);
53 str.append(", path:");
54 str.append(path);
55 str.append(", uri:");
56 str.append(uri);
57 str.append(", id:");
58 str.append(std::to_string(id));
59 return str;
60 }
61 };
62
GetFileInfo(const ExecEnv & env,const std::string & path,std::vector<FileInfo> & fileInfos)63 static inline int32_t GetFileInfo(const ExecEnv &env, const std::string &path, std::vector<FileInfo> &fileInfos)
64 {
65 FileInfo fileInfo;
66 fileInfo.displayName = ExtractFileName(path);
67 fileInfo.mediaType = MediaFileUtils::GetMediaType(fileInfo.displayName);
68 fileInfo.path = path;
69 fileInfo.result = Media::E_ERR;
70 auto mediaTypes = UserFileClientEx::GetSupportTypes();
71 for (auto mediaType : mediaTypes) {
72 if (mediaType != fileInfo.mediaType) {
73 continue;
74 }
75 fileInfos.push_back(fileInfo);
76 return Media::E_OK;
77 }
78 return Media::E_ERR;
79 }
80
GetDirInfo(const ExecEnv & env,const std::string & path,std::vector<FileInfo> & fileInfos)81 static int32_t GetDirInfo(const ExecEnv &env, const std::string &path, std::vector<FileInfo> &fileInfos)
82 {
83 std::vector<std::string> files;
84 GetDirFiles(path, files);
85 if (!files.size() && errno) {
86 printf("%s can not get dir files. errno:%d\n", STR_FAIL.c_str(), errno);
87 }
88 for (auto &file : files) {
89 auto ret = GetFileInfo(env, file, fileInfos);
90 if (ret != Media::E_OK) {
91 printf("%s get dir information failed. ret:%d, file:%s\n", STR_FAIL.c_str(), ret, file.c_str());
92 return ret;
93 }
94 }
95 return Media::E_OK;
96 }
97
RemoveFiles(const ExecEnv & env,std::vector<FileInfo> & fileInfos)98 static void RemoveFiles(const ExecEnv &env, std::vector<FileInfo> &fileInfos)
99 {
100 for (auto &fileInfo : fileInfos) {
101 if (fileInfo.result != Media::E_OK) {
102 continue;
103 }
104 if (!fileInfo.toBeRemove) {
105 continue;
106 }
107 RemoveFile(fileInfo.path);
108 }
109 fileInfos.clear();
110 }
111
EncodeDisplayName(const std::string & displayName)112 static std::string EncodeDisplayName(const std::string &displayName)
113 {
114 std::set<char> CHAR_FILTERS = {
115 '\\', '/', ':',
116 '*', '?', '"',
117 '<', '>', '|',
118 };
119 std::string encodedStr = "";
120 for (char c : displayName) {
121 if (CHAR_FILTERS.find(c) != CHAR_FILTERS.end()) {
122 encodedStr += MediaFileUtils::Encode(string(1, c));
123 } else {
124 encodedStr += c;
125 }
126 }
127 return encodedStr;
128 }
129
CreateRecord(const ExecEnv & env,FileInfo & fileInfo,bool isRestart)130 static int32_t CreateRecord(const ExecEnv &env, FileInfo &fileInfo, bool isRestart)
131 {
132 const MediaType mediaType = fileInfo.mediaType;
133 std::string tableName = UserFileClientEx::GetTableNameByMediaType(mediaType);
134 const std::string displayName = EncodeDisplayName(fileInfo.displayName);
135 string uri;
136 auto fileId = UserFileClientEx::InsertExt(tableName, displayName, uri, isRestart);
137 if (fileId <= 0) {
138 printf("%s create record failed. fileId:%d, fileInfo:%s\n",
139 STR_FAIL.c_str(), fileId, fileInfo.ToStr().c_str());
140 return Media::E_ERR;
141 }
142 if (!uri.empty()) {
143 fileInfo.uri = uri;
144 } else {
145 printf("%s create record failed. uri is empty. fileInfo:%s\n",
146 STR_FAIL.c_str(), fileInfo.ToStr().c_str());
147 return Media::E_FAIL;
148 }
149 fileInfo.id = fileId;
150 return Media::E_OK;
151 }
152
WriteFile(const ExecEnv & env,FileInfo & fileInfo,bool isRestart)153 static int32_t WriteFile(const ExecEnv &env, FileInfo &fileInfo, bool isRestart)
154 {
155 if (!PathToRealPath(fileInfo.path, fileInfo.path)) {
156 printf("%s path issue. errno:%d, path:%s.\n", STR_FAIL.c_str(), errno, fileInfo.path.c_str());
157 return Media::E_ERR;
158 }
159 int32_t rfd = open(fileInfo.path.c_str(), O_RDONLY | O_CLOEXEC);
160 if (rfd < 0) {
161 printf("%s open file failed. rfd:%d, path:%s\n", STR_FAIL.c_str(), rfd, fileInfo.path.c_str());
162 return Media::E_ERR;
163 }
164 int32_t wfd = UserFileClientEx::Open(fileInfo.uri, Media::MEDIA_FILEMODE_WRITETRUNCATE, isRestart);
165 if (wfd <= 0) {
166 printf("%s open failed. wfd:%d, uri:%s\n", STR_FAIL.c_str(), wfd, fileInfo.uri.c_str());
167 close(rfd);
168 return Media::E_ERR;
169 }
170 int32_t ret = MediaFileUtils::CopyFile(rfd, wfd);
171 if (!ret) {
172 printf("%s send data failed. rfd:%d, wfd:%d\n", STR_FAIL.c_str(), rfd, wfd);
173 close(rfd);
174 close(wfd);
175 return Media::E_ERR;
176 }
177 if (env.sendParam.isCreateThumbSyncInSend) {
178 ret = UserFileClientEx::Close(fileInfo.uri, wfd, Media::MEDIA_FILEMODE_WRITETRUNCATE, true, isRestart);
179 } else {
180 ret = UserFileClientEx::Close(fileInfo.uri, wfd, Media::MEDIA_FILEMODE_WRITETRUNCATE, false, isRestart);
181 }
182 if (ret != E_OK) {
183 printf("close file has err [%d]\n", ret);
184 }
185
186 close(rfd);
187 return ret;
188 }
189
190 static constexpr int MAX_RESTART_TIME = 5;
RestartMediaLibraryServer(int32_t restartTime)191 static void RestartMediaLibraryServer(int32_t restartTime)
192 {
193 printf("Run operations failed, restart Time %d\n", restartTime);
194 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_NOTIFY_TIME));
195 }
196
SendFile(const ExecEnv & env,FileInfo & fileInfo)197 static int32_t SendFile(const ExecEnv &env, FileInfo &fileInfo)
198 {
199 int32_t restartTime = 0;
200
201 while (restartTime < MAX_RESTART_TIME) {
202 fileInfo.result = CreateRecord(env, fileInfo, (restartTime > 0) ? true : false);
203 if (fileInfo.result != Media::E_OK) {
204 restartTime++;
205 RestartMediaLibraryServer(restartTime);
206 continue;
207 } else {
208 break;
209 }
210 }
211 if (fileInfo.result != Media::E_OK) {
212 return Media::E_ERR;
213 }
214
215 std::string tableName = UserFileClientEx::GetTableNameByUri(fileInfo.uri);
216 if (tableName.empty()) {
217 printf("%s uri issue. uri:%s\n", STR_FAIL.c_str(), fileInfo.uri.c_str());
218 return Media::E_ERR;
219 }
220
221 while (restartTime < MAX_RESTART_TIME) {
222 fileInfo.result = WriteFile(env, fileInfo, (restartTime > 0) ? true : false);
223 if (fileInfo.result != Media::E_OK) {
224 restartTime++;
225 RestartMediaLibraryServer(restartTime);
226 continue;
227 } else {
228 break;
229 }
230 }
231 if (fileInfo.result != Media::E_OK) {
232 return Media::E_ERR;
233 }
234 fileInfo.result = Media::E_OK;
235 return Media::E_OK;
236 }
237
SendFiles(const ExecEnv & env,std::vector<FileInfo> & fileInfos)238 static int32_t SendFiles(const ExecEnv &env, std::vector<FileInfo> &fileInfos)
239 {
240 int count = 0;
241 int correctCount = 0;
242 for (auto &fileInfo : fileInfos) {
243 ++count;
244 int32_t ret = SendFile(env, fileInfo);
245 if (ret != Media::E_OK) {
246 printf("%s send uri [%s] failed.\n", STR_FAIL.c_str(), fileInfo.uri.c_str());
247 } else {
248 fileInfo.toBeRemove = true;
249 printf("%s\n", fileInfo.uri.c_str());
250 ++correctCount;
251 }
252 }
253
254 if (count > ARGS_ONE) {
255 if (count == correctCount) {
256 printf("%s send %d and %d is successful.\n", STR_SUCCESS.c_str(), count, correctCount);
257 return Media::E_OK;
258 } else {
259 printf("%s send %d and %d is successful.\n", STR_FAIL.c_str(), count, correctCount);
260 return Media::E_FAIL;
261 }
262 } else {
263 if (correctCount == count) {
264 return Media::E_OK;
265 } else {
266 return Media::E_FAIL;
267 }
268 }
269 }
270
Start(const ExecEnv & env)271 int32_t SendCommandV10::Start(const ExecEnv &env)
272 {
273 std::vector<FileInfo> fileInfos;
274 auto ret = (env.sendParam.isFile) ? GetFileInfo(env, env.sendParam.sendPath, fileInfos) : GetDirInfo(env,
275 env.sendParam.sendPath, fileInfos);
276 if (ret != Media::E_OK) {
277 printf("%s get file information failed. ret:%d\n", STR_FAIL.c_str(), ret);
278 return ret;
279 }
280 ret = SendFiles(env, fileInfos);
281 if (env.sendParam.isRemoveOriginFileInSend) {
282 RemoveFiles(env, fileInfos);
283 }
284 return ret;
285 }
286 } // namespace MediaTool
287 } // namespace Media
288 } // namespace OHOS
289