1 /**
2 * Copyright 2020 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/common/file_utils.h"
18 #include <sys/stat.h>
19 #ifdef _WIN32
20 #include <direct.h>
21 #include <io.h>
22 #else
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <dirent.h>
26 #endif
27
28 #include <cstdlib>
29 #include "securec/include/securec.h"
30
31 #ifdef _MSC_VER
32 #define PATH_MAX 1024
33 #define F_OK 0
34 #define R_OK 4
35 #endif
36
37 namespace mindspore {
38 namespace lite {
39 namespace {
40 const int MAXIMUM_NUMBERS_OF_FOLDER = 1000;
41
AccessFile(const std::string & file_path,int access_mode)42 inline int AccessFile(const std::string &file_path, int access_mode) {
43 #ifdef _WIN32
44 return _access(file_path.c_str(), access_mode);
45 #else
46 // android access interface always return true
47 struct stat st;
48 if (stat(file_path.c_str(), &st) == 0) {
49 mode_t perm = st.st_mode;
50 auto can_read = perm & S_IRUSR;
51 return (can_read && access(file_path.c_str(), access_mode) == 0) ? 0 : -1;
52 }
53 return -1;
54 #endif
55 }
56
Mkdir(const std::string & file_path)57 inline int Mkdir(const std::string &file_path) {
58 #ifdef _WIN32
59 return _mkdir(file_path.c_str());
60 #else
61 return mkdir(file_path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
62 #endif
63 }
64 } // namespace
65
IsCharEndWith(const char * src,const char * end)66 bool IsCharEndWith(const char *src, const char *end) {
67 if (strlen(src) > strlen(end)) {
68 const char *src_end = src + (strlen(src) - strlen(end));
69 if (strcmp(src_end, end) == 0) {
70 return true;
71 }
72 }
73 return false;
74 }
75
76 // do not call RealPath function in OpenFile, because OpenFile may open a non-exist file
OpenFile(const std::string & file_path,std::ios_base::openmode open_mode)77 std::fstream *OpenFile(const std::string &file_path, std::ios_base::openmode open_mode) {
78 auto fs = new (std::nothrow) std::fstream();
79 if (fs == nullptr) {
80 MS_LOG(DEBUG) << "Create file stream failed";
81 return nullptr;
82 }
83 fs->open(file_path, open_mode);
84 if (!fs->good()) {
85 MS_LOG(DEBUG) << "File is not exist: " << file_path;
86 delete fs;
87 return nullptr;
88 }
89 if (!fs->is_open()) {
90 MS_LOG(DEBUG) << "Can not open file: " << file_path;
91 delete fs;
92 return nullptr;
93 }
94 return fs;
95 }
96
97 // read file in [offset, offset + len)
ReadFileSegment(const std::string & file,int64_t offset,int64_t len)98 char *ReadFileSegment(const std::string &file, int64_t offset, int64_t len) {
99 if (len <= 0) {
100 return nullptr;
101 }
102 auto len_pos = static_cast<size_t>(len);
103 if (offset < 0) {
104 MS_LOG(DEBUG) << "offset is invalid, offset: " << offset;
105 return nullptr;
106 }
107 auto offset_pos = static_cast<size_t>(offset);
108 std::string real_path = lite::RealPath(file.c_str());
109 if (lite::AccessFile(real_path, R_OK) != 0) {
110 MS_LOG(DEBUG) << "cannot access file:" << real_path << ".please check file if exists and file mod";
111 return nullptr;
112 }
113 std::ifstream ifs(real_path, std::ifstream::in | std::ifstream::binary);
114 if (!ifs.good()) {
115 MS_LOG(DEBUG) << "file: " << real_path << " is not exist";
116 return nullptr;
117 }
118
119 if (!ifs.is_open()) {
120 MS_LOG(DEBUG) << "file: " << real_path << " open failed";
121 return nullptr;
122 }
123
124 ifs.seekg(0, std::ios::end);
125 auto goffset = ifs.tellg();
126 if (goffset < 0) {
127 MS_LOG(ERROR) << "read file range failed";
128 ifs.close();
129 return nullptr;
130 }
131 size_t total_size = static_cast<size_t>(goffset);
132 if (offset_pos + len_pos > total_size) {
133 MS_LOG(ERROR) << "file segment out of range";
134 ifs.close();
135 return nullptr;
136 }
137
138 auto buf = reinterpret_cast<char *>(malloc(len));
139 if (buf == nullptr) {
140 MS_LOG(ERROR) << "malloc buf failed, file: " << real_path;
141 ifs.close();
142 return nullptr;
143 }
144
145 ifs.seekg(offset, std::ios::beg);
146 ifs.read(buf, len);
147 ifs.close();
148
149 return buf;
150 }
151
ReadFile(const char * file,size_t * size,std::shared_ptr<Allocator> allocator)152 char *ReadFile(const char *file, size_t *size, std::shared_ptr<Allocator> allocator) {
153 if (file == nullptr) {
154 MS_LOG(ERROR) << "File path is nullptr";
155 return nullptr;
156 }
157 MS_ASSERT(size != nullptr);
158 std::string real_path = RealPath(file);
159 if (real_path.empty()) {
160 MS_LOG(DEBUG) << "File path not regular: " << file;
161 return nullptr;
162 }
163 #ifndef _MSC_VER
164 if (access(real_path.c_str(), F_OK) != 0) {
165 MS_LOG(ERROR) << "File is not exist: " << real_path;
166 return nullptr;
167 }
168 if (access(real_path.c_str(), R_OK) != 0) {
169 MS_LOG(ERROR) << "File " << real_path << " can't be read. Please change the file permission.";
170 return nullptr;
171 }
172 #endif
173 auto ifs = OpenFile(real_path, std::ifstream::in | std::ifstream::binary);
174 if (ifs == nullptr) {
175 MS_LOG(ERROR) << "Open file failed.";
176 return nullptr;
177 }
178
179 ifs->seekg(0, std::ios::end);
180 auto goffset = ifs->tellg();
181 if (goffset < 0) {
182 MS_LOG(ERROR) << "read file range failed";
183 ifs->close();
184 delete ifs;
185 return nullptr;
186 }
187 *size = static_cast<size_t>(goffset);
188 char *model_buf = nullptr;
189 if (allocator != nullptr) {
190 MS_LOG(INFO) << "read ms model buf in numa 0.";
191 auto buf = allocator->Malloc(*size);
192 model_buf = static_cast<char *>(buf);
193 } else {
194 model_buf = new (std::nothrow) char[*size];
195 }
196 if (model_buf == nullptr) {
197 MS_LOG(ERROR) << "malloc buf failed, file: " << file;
198 ifs->close();
199 delete ifs;
200 return nullptr;
201 }
202
203 ifs->seekg(0, std::ios::beg);
204 ifs->read(model_buf, *size);
205 ifs->close();
206 delete ifs;
207 return model_buf;
208 }
209
RealPath(const char * path)210 std::string RealPath(const char *path) {
211 if (path == nullptr) {
212 MS_LOG(ERROR) << "path is nullptr";
213 return "";
214 }
215 if ((strlen(path)) >= PATH_MAX) {
216 MS_LOG(ERROR) << "path is too long";
217 return "";
218 }
219 auto resolved_path = std::make_unique<char[]>(PATH_MAX);
220 if (resolved_path == nullptr) {
221 MS_LOG(ERROR) << "new resolved_path failed";
222 return "";
223 }
224 #ifdef _WIN32
225 char *real_path = _fullpath(resolved_path.get(), path, PATH_MAX);
226 #else
227 char *real_path = realpath(path, resolved_path.get());
228 #endif
229 if (real_path == nullptr || strlen(real_path) == 0) {
230 MS_LOG(ERROR) << "file path not exists: " << path;
231 return "";
232 }
233 std::string res = resolved_path.get();
234 return res;
235 }
236
CreateDir(const std::string & file_path)237 int CreateDir(const std::string &file_path) {
238 if (file_path.empty()) {
239 MS_LOG(ERROR) << "input file path is empty.";
240 return RET_ERROR;
241 } else if (file_path.size() >= PATH_MAX) {
242 MS_LOG(ERROR) << "input file path is too long";
243 return RET_ERROR;
244 }
245
246 for (size_t i = 0; i < file_path.size(); i++) {
247 if (file_path.at(i) == '\\' || file_path.at(i) == '/') {
248 if (AccessFile(file_path.substr(0, i + 1), F_OK) != 0) {
249 int ret = Mkdir(file_path.substr(0, i + 1));
250 if (ret != RET_OK) {
251 MS_LOG(ERROR) << "mkdir failed. " << file_path.substr(0, i + 1);
252 return RET_ERROR;
253 }
254 }
255 }
256 }
257
258 if (file_path.back() != '\\' && file_path.back() != '/') {
259 if (AccessFile(file_path, F_OK) != 0) {
260 int ret = Mkdir(file_path);
261 if (ret != RET_OK) {
262 MS_LOG(ERROR) << "mkdir failed. " << file_path;
263 return RET_ERROR;
264 }
265 }
266 }
267 return RET_OK;
268 }
269
CreateOutputDir(std::string * file_path)270 int CreateOutputDir(std::string *file_path) {
271 if (CreateDir(*file_path) != RET_OK) {
272 MS_LOG(ERROR) << "Create file dir failed";
273 return RET_ERROR;
274 }
275
276 int count = 0;
277 while (AccessFile((*file_path + "/" + std::to_string(count)), F_OK) == 0) {
278 MS_LOG(INFO) << "current file_path has existed, file_path cnt plus 1."; // such as: /xxx/0 ==> /xxx/1
279 count++;
280 if (count >= MAXIMUM_NUMBERS_OF_FOLDER) {
281 MS_LOG(ERROR) << "the number of file folders exceeds the upper limit.";
282 return RET_ERROR;
283 }
284 }
285 #ifdef _WIN32
286 *file_path += "\\" + std::to_string(count);
287 #else
288 *file_path += "/" + std::to_string(count);
289 #endif
290 int ret = Mkdir(*file_path);
291 if (ret != RET_OK) {
292 MS_LOG(ERROR) << "mkdir failed. " << file_path->c_str();
293 return RET_ERROR;
294 }
295 return RET_OK;
296 }
297
GetDirectory(const std::string & path)298 std::string GetDirectory(const std::string &path) {
299 auto pos = path.find_last_of('/');
300 if (pos == std::string::npos) {
301 pos = path.find_last_of('\\');
302 }
303 std::string dir;
304 if (pos != std::string::npos) {
305 dir = path.substr(0, pos + 1);
306 }
307 return dir;
308 }
309
ParserPathAndModelName(const std::string & output_path,std::string * save_path,std::string * model_name)310 bool ParserPathAndModelName(const std::string &output_path, std::string *save_path, std::string *model_name) {
311 auto pos = output_path.find_last_of('/');
312 if (pos == std::string::npos) {
313 pos = output_path.find_last_of('\\');
314 }
315 std::string tmp_model_name;
316 if (pos == std::string::npos) {
317 #ifdef _WIN32
318 *save_path = ".\\";
319 #else
320 *save_path = "./";
321 #endif
322 tmp_model_name = output_path;
323 } else {
324 *save_path = output_path.substr(0, pos + 1);
325 tmp_model_name = output_path.substr(pos + 1);
326 }
327 *save_path = RealPath(save_path->c_str());
328 if (save_path->empty()) {
329 MS_LOG(DEBUG) << "File path not regular: " << save_path;
330 return false;
331 }
332 auto suffix_pos = tmp_model_name.find_last_of('.');
333 if (suffix_pos == std::string::npos) {
334 *model_name = tmp_model_name;
335 } else {
336 if (tmp_model_name.substr(suffix_pos + 1) == "ms") {
337 *model_name = tmp_model_name.substr(0, suffix_pos);
338 } else {
339 *model_name = tmp_model_name;
340 }
341 }
342 return true;
343 }
344 } // namespace lite
345 } // namespace mindspore
346