1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "test/testsupport/file_utils.h"
12
13
14 #if defined(WEBRTC_POSIX)
15 #include <unistd.h>
16 #endif
17
18 #if defined(WEBRTC_WIN)
19 #include <direct.h>
20 #include <tchar.h>
21 #include <windows.h>
22
23 #include <algorithm>
24 #include <codecvt>
25 #include <locale>
26
27 #include "Shlwapi.h"
28 #include "WinDef.h"
29 #include "rtc_base/win32.h"
30
31 #define GET_CURRENT_DIR _getcwd
32 #else
33 #include <dirent.h>
34
35 #define GET_CURRENT_DIR getcwd
36 #endif
37
38 #include <sys/stat.h> // To check for directory existence.
39 #ifndef S_ISDIR // Not defined in stat.h on Windows.
40 #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
41 #endif
42
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 #include <memory>
47 #include <type_traits>
48 #include <utility>
49
50 #if defined(WEBRTC_IOS)
51 #include "test/testsupport/ios_file_utils.h"
52 #elif defined(WEBRTC_MAC)
53 #include "test/testsupport/mac_file_utils.h"
54 #endif
55
56 #include "absl/strings/string_view.h"
57 #include "rtc_base/checks.h"
58 #include "rtc_base/string_utils.h"
59 #include "rtc_base/strings/string_builder.h"
60 #include "test/testsupport/file_utils_override.h"
61
62 namespace webrtc {
63 namespace test {
64
65 #if defined(WEBRTC_WIN)
66 ABSL_CONST_INIT const absl::string_view kPathDelimiter = "\\";
67 #else
68 ABSL_CONST_INIT const absl::string_view kPathDelimiter = "/";
69 #endif
70
DirName(absl::string_view path)71 std::string DirName(absl::string_view path) {
72 if (path.empty())
73 return "";
74 if (path == kPathDelimiter)
75 return std::string(path);
76
77 if (path.back() == kPathDelimiter[0])
78 path.remove_suffix(1); // Remove trailing separator.
79
80 return std::string(path.substr(0, path.find_last_of(kPathDelimiter)));
81 }
82
FileExists(absl::string_view file_name)83 bool FileExists(absl::string_view file_name) {
84 struct stat file_info = {0};
85 return stat(std::string(file_name).c_str(), &file_info) == 0;
86 }
87
DirExists(absl::string_view directory_name)88 bool DirExists(absl::string_view directory_name) {
89 struct stat directory_info = {0};
90 return stat(std::string(directory_name).c_str(), &directory_info) == 0 &&
91 S_ISDIR(directory_info.st_mode);
92 }
93
OutputPath()94 std::string OutputPath() {
95 return webrtc::test::internal::OutputPath();
96 }
97
WorkingDir()98 std::string WorkingDir() {
99 return webrtc::test::internal::WorkingDir();
100 }
101
102 // Generate a temporary filename in a safe way.
103 // Largely copied from talk/base/{unixfilesystem,win32filesystem}.cc.
TempFilename(absl::string_view dir,absl::string_view prefix)104 std::string TempFilename(absl::string_view dir, absl::string_view prefix) {
105 #ifdef WIN32
106 wchar_t filename[MAX_PATH];
107 if (::GetTempFileNameW(rtc::ToUtf16(dir).c_str(),
108 rtc::ToUtf16(prefix).c_str(), 0, filename) != 0)
109 return rtc::ToUtf8(filename);
110 RTC_DCHECK_NOTREACHED();
111 return "";
112 #else
113 rtc::StringBuilder os;
114 os << dir << "/" << prefix << "XXXXXX";
115 std::string tempname = os.Release();
116
117 int fd = ::mkstemp(tempname.data());
118 if (fd == -1) {
119 RTC_DCHECK_NOTREACHED();
120 return "";
121 } else {
122 ::close(fd);
123 }
124 return tempname;
125 #endif
126 }
127
GenerateTempFilename(absl::string_view dir,absl::string_view prefix)128 std::string GenerateTempFilename(absl::string_view dir,
129 absl::string_view prefix) {
130 std::string filename = TempFilename(dir, prefix);
131 RemoveFile(filename);
132 return filename;
133 }
134
ReadDirectory(absl::string_view path)135 absl::optional<std::vector<std::string>> ReadDirectory(absl::string_view path) {
136 if (path.length() == 0)
137 return absl::optional<std::vector<std::string>>();
138
139 std::string path_str(path);
140
141 #if defined(WEBRTC_WIN)
142 // Append separator character if needed.
143 if (path_str.back() != '\\')
144 path_str += '\\';
145
146 // Init.
147 WIN32_FIND_DATAW data;
148 HANDLE handle = ::FindFirstFileW(rtc::ToUtf16(path_str + '*').c_str(), &data);
149 if (handle == INVALID_HANDLE_VALUE)
150 return absl::optional<std::vector<std::string>>();
151
152 // Populate output.
153 std::vector<std::string> found_entries;
154 do {
155 const std::string name = rtc::ToUtf8(data.cFileName);
156 if (name != "." && name != "..")
157 found_entries.emplace_back(path_str + name);
158 } while (::FindNextFileW(handle, &data) == TRUE);
159
160 // Release resources.
161 if (handle != INVALID_HANDLE_VALUE)
162 ::FindClose(handle);
163 #else
164 // Append separator character if needed.
165 if (path_str.back() != '/')
166 path_str += '/';
167
168 // Init.
169 DIR* dir = ::opendir(path_str.c_str());
170 if (dir == nullptr)
171 return absl::optional<std::vector<std::string>>();
172
173 // Populate output.
174 std::vector<std::string> found_entries;
175 while (dirent* dirent = readdir(dir)) {
176 const std::string& name = dirent->d_name;
177 if (name != "." && name != "..")
178 found_entries.emplace_back(path_str + name);
179 }
180
181 // Release resources.
182 closedir(dir);
183 #endif
184
185 return absl::optional<std::vector<std::string>>(std::move(found_entries));
186 }
187
CreateDir(absl::string_view directory_name)188 bool CreateDir(absl::string_view directory_name) {
189 std::string directory_name_str(directory_name);
190 struct stat path_info = {0};
191 // Check if the path exists already:
192 if (stat(directory_name_str.c_str(), &path_info) == 0) {
193 if (!S_ISDIR(path_info.st_mode)) {
194 fprintf(stderr,
195 "Path %s exists but is not a directory! Remove this "
196 "file and re-run to create the directory.\n",
197 directory_name_str.c_str());
198 return false;
199 }
200 } else {
201 #ifdef WIN32
202 return _mkdir(directory_name_str.c_str()) == 0;
203 #else
204 return mkdir(directory_name_str.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0;
205 #endif
206 }
207 return true;
208 }
209
RemoveDir(absl::string_view directory_name)210 bool RemoveDir(absl::string_view directory_name) {
211 #ifdef WIN32
212 return RemoveDirectoryA(std::string(directory_name).c_str()) != FALSE;
213 #else
214 return rmdir(std::string(directory_name).c_str()) == 0;
215 #endif
216 }
217
RemoveFile(absl::string_view file_name)218 bool RemoveFile(absl::string_view file_name) {
219 #ifdef WIN32
220 return DeleteFileA(std::string(file_name).c_str()) != FALSE;
221 #else
222 return unlink(std::string(file_name).c_str()) == 0;
223 #endif
224 }
225
ResourcePath(absl::string_view name,absl::string_view extension)226 std::string ResourcePath(absl::string_view name, absl::string_view extension) {
227 return webrtc::test::internal::ResourcePath(name, extension);
228 }
229
JoinFilename(absl::string_view dir,absl::string_view name)230 std::string JoinFilename(absl::string_view dir, absl::string_view name) {
231 RTC_CHECK(!dir.empty()) << "Special cases not implemented.";
232 rtc::StringBuilder os;
233 os << dir << kPathDelimiter << name;
234 return os.Release();
235 }
236
GetFileSize(absl::string_view filename)237 size_t GetFileSize(absl::string_view filename) {
238 FILE* f = fopen(std::string(filename).c_str(), "rb");
239 size_t size = 0;
240 if (f != NULL) {
241 if (fseek(f, 0, SEEK_END) == 0) {
242 size = ftell(f);
243 }
244 fclose(f);
245 }
246 return size;
247 }
248
249 } // namespace test
250 } // namespace webrtc
251