• 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/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 inline 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     for (auto &file : files) {
86         auto ret = GetFileInfo(env, file, fileInfos);
87         if (ret != Media::E_OK) {
88             printf("%s get dir information failed. ret:%d, file:%s\n", STR_FAIL.c_str(), ret, file.c_str());
89             return ret;
90         }
91     }
92     return Media::E_OK;
93 }
94 
RemoveFiles(const ExecEnv & env,std::vector<FileInfo> & fileInfos)95 static void RemoveFiles(const ExecEnv &env, std::vector<FileInfo> &fileInfos)
96 {
97     for (auto &fileInfo : fileInfos) {
98         if (fileInfo.result != Media::E_OK) {
99             continue;
100         }
101         if (!fileInfo.toBeRemove) {
102             continue;
103         }
104         RemoveFile(fileInfo.path);
105     }
106     fileInfos.clear();
107 }
108 
EncodeDisplayName(const std::string & displayName)109 static std::string EncodeDisplayName(const std::string &displayName)
110 {
111     std::set<char> CHAR_FILTERS = {
112         '.', '\\', '/', ':',
113         '*', '?', '"', '\'',
114         '`', '<', '>', '|',
115         '{', '}', '[', ']' };
116     std::string encodedStr = "";
117     for (char c : displayName) {
118         if (CHAR_FILTERS.find(c) != CHAR_FILTERS.end()) {
119             encodedStr += MediaFileUtils::Encode(string(1, c));
120         } else {
121             encodedStr += c;
122         }
123     }
124     return encodedStr;
125 }
126 
CreateRecord(const ExecEnv & env,FileInfo & fileInfo,bool isRestart)127 static int32_t CreateRecord(const ExecEnv &env, FileInfo &fileInfo, bool isRestart)
128 {
129     const MediaType mediaType = fileInfo.mediaType;
130     std::string tableName = UserFileClientEx::GetTableNameByMediaType(mediaType);
131     const std::string displayName = EncodeDisplayName(fileInfo.displayName);
132     string uri;
133     auto fileId = UserFileClientEx::InsertExt(tableName, displayName, uri, isRestart);
134     if (fileId <= 0) {
135         printf("%s create record failed. fileId:%d, fileInfo:%s\n",
136             STR_FAIL.c_str(), fileId, fileInfo.ToStr().c_str());
137         return Media::E_ERR;
138     }
139     if (!uri.empty()) {
140         fileInfo.uri = uri;
141     } else {
142         printf("%s create record failed. uri is empty. fileInfo:%s\n",
143             STR_FAIL.c_str(), fileInfo.ToStr().c_str());
144         return Media::E_FAIL;
145     }
146     fileInfo.id = fileId;
147     return Media::E_OK;
148 }
149 
WriteFile(const ExecEnv & env,const FileInfo & fileInfo,bool isRestart)150 static int32_t WriteFile(const ExecEnv &env, const FileInfo &fileInfo, bool isRestart)
151 {
152     int32_t rfd = open(fileInfo.path.c_str(), O_RDONLY | O_CLOEXEC);
153     if (rfd < 0) {
154         printf("%s open file failed. rfd:%d, path:%s\n", STR_FAIL.c_str(), rfd, fileInfo.path.c_str());
155         return Media::E_ERR;
156     }
157     int32_t wfd = UserFileClientEx::Open(fileInfo.uri, Media::MEDIA_FILEMODE_WRITETRUNCATE, isRestart);
158     if (wfd <= 0) {
159         printf("%s open failed. wfd:%d, uri:%s\n", STR_FAIL.c_str(), wfd, fileInfo.uri.c_str());
160         close(rfd);
161         return Media::E_ERR;
162     }
163     int32_t ret = MediaFileUtils::CopyFile(rfd, wfd);
164     if (!ret) {
165         printf("%s send data failed. rfd:%d, wfd:%d\n", STR_FAIL.c_str(), rfd, wfd);
166         close(rfd);
167         close(wfd);
168         return Media::E_ERR;
169     }
170     if (env.sendParam.isCreateThumbSyncInSend) {
171         ret = UserFileClientEx::Close(fileInfo.uri, wfd, Media::MEDIA_FILEMODE_WRITETRUNCATE, true, isRestart);
172     } else {
173         ret = UserFileClientEx::Close(fileInfo.uri, wfd, Media::MEDIA_FILEMODE_WRITETRUNCATE, false, isRestart);
174     }
175     if (ret != E_OK) {
176         printf("close file has err [%d]\n", ret);
177     }
178 
179     close(rfd);
180     return ret;
181 }
182 
183 static constexpr int MAX_RESTART_TIME = 5;
RestartMediaLibraryServer(int32_t restartTime)184 static void RestartMediaLibraryServer(int32_t restartTime)
185 {
186     printf("Run operations failed, restart Time %d\n", restartTime);
187     std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_NOTIFY_TIME));
188 }
189 
SendFile(const ExecEnv & env,FileInfo & fileInfo)190 static int32_t SendFile(const ExecEnv &env, FileInfo &fileInfo)
191 {
192     int32_t restartTime = 0;
193 
194     while (restartTime < MAX_RESTART_TIME) {
195         fileInfo.result = CreateRecord(env, fileInfo, (restartTime > 0) ? true : false);
196         if (fileInfo.result != Media::E_OK) {
197             restartTime++;
198             RestartMediaLibraryServer(restartTime);
199             continue;
200         } else {
201             break;
202         }
203     }
204     if (fileInfo.result != Media::E_OK) {
205         return Media::E_ERR;
206     }
207 
208     std::string tableName = UserFileClientEx::GetTableNameByUri(fileInfo.uri);
209     if (tableName.empty()) {
210         printf("%s uri issue. uri:%s\n", STR_FAIL.c_str(), fileInfo.uri.c_str());
211         return Media::E_ERR;
212     }
213 
214     while (restartTime < MAX_RESTART_TIME) {
215         fileInfo.result = WriteFile(env, fileInfo, (restartTime > 0) ? true : false);
216         if (fileInfo.result != Media::E_OK) {
217             restartTime++;
218             RestartMediaLibraryServer(restartTime);
219             continue;
220         } else {
221             break;
222         }
223     }
224     if (fileInfo.result != Media::E_OK) {
225         return Media::E_ERR;
226     }
227     fileInfo.result = Media::E_OK;
228     return Media::E_OK;
229 }
230 
SendFiles(const ExecEnv & env,std::vector<FileInfo> & fileInfos)231 static int32_t SendFiles(const ExecEnv &env, std::vector<FileInfo> &fileInfos)
232 {
233     int count = 0;
234     int correctCount = 0;
235     for (auto &fileInfo : fileInfos) {
236         ++count;
237         int32_t ret = SendFile(env, fileInfo);
238         if (ret != Media::E_OK) {
239             printf("%s send uri [%s] failed.\n", STR_FAIL.c_str(), fileInfo.uri.c_str());
240         } else {
241             fileInfo.toBeRemove = true;
242             printf("%s\n", fileInfo.uri.c_str());
243             ++correctCount;
244         }
245     }
246 
247     if (count > ARGS_ONE) {
248         if (count == correctCount) {
249             printf("%s send %d and %d is successful.\n", STR_SUCCESS.c_str(), count, correctCount);
250             return Media::E_OK;
251         } else {
252             printf("%s send %d and %d is successful.\n", STR_FAIL.c_str(), count, correctCount);
253             return Media::E_FAIL;
254         }
255     } else {
256         if (correctCount == count) {
257             return Media::E_OK;
258         } else {
259             return Media::E_FAIL;
260         }
261     }
262 }
263 
Start(const ExecEnv & env)264 int32_t SendCommandV10::Start(const ExecEnv &env)
265 {
266     std::vector<FileInfo> fileInfos;
267     auto ret = (env.sendParam.isFile) ? GetFileInfo(env, env.sendParam.sendPath, fileInfos) : GetDirInfo(env,
268         env.sendParam.sendPath, fileInfos);
269     if (ret != Media::E_OK) {
270         printf("%s get file information failed. ret:%d\n", STR_FAIL.c_str(), ret);
271         return ret;
272     }
273     ret = SendFiles(env, fileInfos);
274     if (env.sendParam.isRemoveOriginFileInSend) {
275         RemoveFiles(env, fileInfos);
276     }
277     return ret;
278 }
279 } // namespace MediaTool
280 } // namespace Media
281 } // namespace OHOS
282