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,const FileInfo & fileInfo,bool isRestart)153 static int32_t WriteFile(const ExecEnv &env, const FileInfo &fileInfo, bool isRestart)
154 {
155 int32_t rfd = open(fileInfo.path.c_str(), O_RDONLY | O_CLOEXEC);
156 if (rfd < 0) {
157 printf("%s open file failed. rfd:%d, path:%s\n", STR_FAIL.c_str(), rfd, fileInfo.path.c_str());
158 return Media::E_ERR;
159 }
160 int32_t wfd = UserFileClientEx::Open(fileInfo.uri, Media::MEDIA_FILEMODE_WRITETRUNCATE, isRestart);
161 if (wfd <= 0) {
162 printf("%s open failed. wfd:%d, uri:%s\n", STR_FAIL.c_str(), wfd, fileInfo.uri.c_str());
163 close(rfd);
164 return Media::E_ERR;
165 }
166 int32_t ret = MediaFileUtils::CopyFile(rfd, wfd);
167 if (!ret) {
168 printf("%s send data failed. rfd:%d, wfd:%d\n", STR_FAIL.c_str(), rfd, wfd);
169 close(rfd);
170 close(wfd);
171 return Media::E_ERR;
172 }
173 if (env.sendParam.isCreateThumbSyncInSend) {
174 ret = UserFileClientEx::Close(fileInfo.uri, wfd, Media::MEDIA_FILEMODE_WRITETRUNCATE, true, isRestart);
175 } else {
176 ret = UserFileClientEx::Close(fileInfo.uri, wfd, Media::MEDIA_FILEMODE_WRITETRUNCATE, false, isRestart);
177 }
178 if (ret != E_OK) {
179 printf("close file has err [%d]\n", ret);
180 }
181
182 close(rfd);
183 return ret;
184 }
185
186 static constexpr int MAX_RESTART_TIME = 5;
RestartMediaLibraryServer(int32_t restartTime)187 static void RestartMediaLibraryServer(int32_t restartTime)
188 {
189 printf("Run operations failed, restart Time %d\n", restartTime);
190 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_NOTIFY_TIME));
191 }
192
SendFile(const ExecEnv & env,FileInfo & fileInfo)193 static int32_t SendFile(const ExecEnv &env, FileInfo &fileInfo)
194 {
195 int32_t restartTime = 0;
196
197 while (restartTime < MAX_RESTART_TIME) {
198 fileInfo.result = CreateRecord(env, fileInfo, (restartTime > 0) ? true : false);
199 if (fileInfo.result != Media::E_OK) {
200 restartTime++;
201 RestartMediaLibraryServer(restartTime);
202 continue;
203 } else {
204 break;
205 }
206 }
207 if (fileInfo.result != Media::E_OK) {
208 return Media::E_ERR;
209 }
210
211 std::string tableName = UserFileClientEx::GetTableNameByUri(fileInfo.uri);
212 if (tableName.empty()) {
213 printf("%s uri issue. uri:%s\n", STR_FAIL.c_str(), fileInfo.uri.c_str());
214 return Media::E_ERR;
215 }
216
217 while (restartTime < MAX_RESTART_TIME) {
218 fileInfo.result = WriteFile(env, fileInfo, (restartTime > 0) ? true : false);
219 if (fileInfo.result != Media::E_OK) {
220 restartTime++;
221 RestartMediaLibraryServer(restartTime);
222 continue;
223 } else {
224 break;
225 }
226 }
227 if (fileInfo.result != Media::E_OK) {
228 return Media::E_ERR;
229 }
230 fileInfo.result = Media::E_OK;
231 return Media::E_OK;
232 }
233
SendFiles(const ExecEnv & env,std::vector<FileInfo> & fileInfos)234 static int32_t SendFiles(const ExecEnv &env, std::vector<FileInfo> &fileInfos)
235 {
236 int count = 0;
237 int correctCount = 0;
238 for (auto &fileInfo : fileInfos) {
239 ++count;
240 int32_t ret = SendFile(env, fileInfo);
241 if (ret != Media::E_OK) {
242 printf("%s send uri [%s] failed.\n", STR_FAIL.c_str(), fileInfo.uri.c_str());
243 } else {
244 fileInfo.toBeRemove = true;
245 printf("%s\n", fileInfo.uri.c_str());
246 ++correctCount;
247 }
248 }
249
250 if (count > ARGS_ONE) {
251 if (count == correctCount) {
252 printf("%s send %d and %d is successful.\n", STR_SUCCESS.c_str(), count, correctCount);
253 return Media::E_OK;
254 } else {
255 printf("%s send %d and %d is successful.\n", STR_FAIL.c_str(), count, correctCount);
256 return Media::E_FAIL;
257 }
258 } else {
259 if (correctCount == count) {
260 return Media::E_OK;
261 } else {
262 return Media::E_FAIL;
263 }
264 }
265 }
266
Start(const ExecEnv & env)267 int32_t SendCommandV10::Start(const ExecEnv &env)
268 {
269 std::vector<FileInfo> fileInfos;
270 auto ret = (env.sendParam.isFile) ? GetFileInfo(env, env.sendParam.sendPath, fileInfos) : GetDirInfo(env,
271 env.sendParam.sendPath, fileInfos);
272 if (ret != Media::E_OK) {
273 printf("%s get file information failed. ret:%d\n", STR_FAIL.c_str(), ret);
274 return ret;
275 }
276 ret = SendFiles(env, fileInfos);
277 if (env.sendParam.isRemoveOriginFileInSend) {
278 RemoveFiles(env, fileInfos);
279 }
280 return ret;
281 }
282 } // namespace MediaTool
283 } // namespace Media
284 } // namespace OHOS
285