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 #include <assert.h>
14
15 #if defined(WEBRTC_POSIX)
16 #include <unistd.h>
17 #endif
18
19 #if defined(WEBRTC_WIN)
20 #include <direct.h>
21 #include <tchar.h>
22 #include <windows.h>
23
24 #include <algorithm>
25 #include <codecvt>
26 #include <locale>
27
28 #include "Shlwapi.h"
29 #include "WinDef.h"
30 #include "rtc_base/win32.h"
31
32 #define GET_CURRENT_DIR _getcwd
33 #else
34 #include <dirent.h>
35
36 #define GET_CURRENT_DIR getcwd
37 #endif
38
39 #include <sys/stat.h> // To check for directory existence.
40 #ifndef S_ISDIR // Not defined in stat.h on Windows.
41 #define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
42 #endif
43
44 #include <stdio.h>
45 #include <stdlib.h>
46
47 #include <memory>
48 #include <type_traits>
49 #include <utility>
50
51 #if defined(WEBRTC_IOS)
52 #include "test/testsupport/ios_file_utils.h"
53 #elif defined(WEBRTC_MAC)
54 #include "test/testsupport/mac_file_utils.h"
55 #endif
56
57 #include "rtc_base/checks.h"
58 #include "rtc_base/string_utils.h"
59 #include "test/testsupport/file_utils_override.h"
60
61 namespace webrtc {
62 namespace test {
63
64 #if defined(WEBRTC_WIN)
65 const char* kPathDelimiter = "\\";
66 #else
67 const char* kPathDelimiter = "/";
68 #endif
69
DirName(const std::string & path)70 std::string DirName(const std::string& path) {
71 if (path.empty())
72 return "";
73 if (path == kPathDelimiter)
74 return path;
75
76 std::string result = path;
77 if (result.back() == *kPathDelimiter)
78 result.pop_back(); // Remove trailing separator.
79
80 return result.substr(0, result.find_last_of(kPathDelimiter));
81 }
82
FileExists(const std::string & file_name)83 bool FileExists(const std::string& file_name) {
84 struct stat file_info = {0};
85 return stat(file_name.c_str(), &file_info) == 0;
86 }
87
DirExists(const std::string & directory_name)88 bool DirExists(const std::string& directory_name) {
89 struct stat directory_info = {0};
90 return stat(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(const std::string & dir,const std::string & prefix)104 std::string TempFilename(const std::string& dir, const std::string& 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 assert(false);
111 return "";
112 #else
113 int len = dir.size() + prefix.size() + 2 + 6;
114 std::unique_ptr<char[]> tempname(new char[len]);
115
116 snprintf(tempname.get(), len, "%s/%sXXXXXX", dir.c_str(), prefix.c_str());
117 int fd = ::mkstemp(tempname.get());
118 if (fd == -1) {
119 assert(false);
120 return "";
121 } else {
122 ::close(fd);
123 }
124 std::string ret(tempname.get());
125 return ret;
126 #endif
127 }
128
GenerateTempFilename(const std::string & dir,const std::string & prefix)129 std::string GenerateTempFilename(const std::string& dir,
130 const std::string& prefix) {
131 std::string filename = TempFilename(dir, prefix);
132 RemoveFile(filename);
133 return filename;
134 }
135
ReadDirectory(std::string path)136 absl::optional<std::vector<std::string>> ReadDirectory(std::string path) {
137 if (path.length() == 0)
138 return absl::optional<std::vector<std::string>>();
139
140 #if defined(WEBRTC_WIN)
141 // Append separator character if needed.
142 if (path.back() != '\\')
143 path += '\\';
144
145 // Init.
146 WIN32_FIND_DATAW data;
147 HANDLE handle = ::FindFirstFileW(rtc::ToUtf16(path + '*').c_str(), &data);
148 if (handle == INVALID_HANDLE_VALUE)
149 return absl::optional<std::vector<std::string>>();
150
151 // Populate output.
152 std::vector<std::string> found_entries;
153 do {
154 const std::string name = rtc::ToUtf8(data.cFileName);
155 if (name != "." && name != "..")
156 found_entries.emplace_back(path + name);
157 } while (::FindNextFileW(handle, &data) == TRUE);
158
159 // Release resources.
160 if (handle != INVALID_HANDLE_VALUE)
161 ::FindClose(handle);
162 #else
163 // Append separator character if needed.
164 if (path.back() != '/')
165 path += '/';
166
167 // Init.
168 DIR* dir = ::opendir(path.c_str());
169 if (dir == nullptr)
170 return absl::optional<std::vector<std::string>>();
171
172 // Populate output.
173 std::vector<std::string> found_entries;
174 while (dirent* dirent = readdir(dir)) {
175 const std::string& name = dirent->d_name;
176 if (name != "." && name != "..")
177 found_entries.emplace_back(path + name);
178 }
179
180 // Release resources.
181 closedir(dir);
182 #endif
183
184 return absl::optional<std::vector<std::string>>(std::move(found_entries));
185 }
186
CreateDir(const std::string & directory_name)187 bool CreateDir(const std::string& directory_name) {
188 struct stat path_info = {0};
189 // Check if the path exists already:
190 if (stat(directory_name.c_str(), &path_info) == 0) {
191 if (!S_ISDIR(path_info.st_mode)) {
192 fprintf(stderr,
193 "Path %s exists but is not a directory! Remove this "
194 "file and re-run to create the directory.\n",
195 directory_name.c_str());
196 return false;
197 }
198 } else {
199 #ifdef WIN32
200 return _mkdir(directory_name.c_str()) == 0;
201 #else
202 return mkdir(directory_name.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0;
203 #endif
204 }
205 return true;
206 }
207
RemoveDir(const std::string & directory_name)208 bool RemoveDir(const std::string& directory_name) {
209 #ifdef WIN32
210 return RemoveDirectoryA(directory_name.c_str()) != FALSE;
211 #else
212 return rmdir(directory_name.c_str()) == 0;
213 #endif
214 }
215
RemoveFile(const std::string & file_name)216 bool RemoveFile(const std::string& file_name) {
217 #ifdef WIN32
218 return DeleteFileA(file_name.c_str()) != FALSE;
219 #else
220 return unlink(file_name.c_str()) == 0;
221 #endif
222 }
223
ResourcePath(const std::string & name,const std::string & extension)224 std::string ResourcePath(const std::string& name,
225 const std::string& extension) {
226 return webrtc::test::internal::ResourcePath(name, extension);
227 }
228
JoinFilename(const std::string & dir,const std::string & name)229 std::string JoinFilename(const std::string& dir, const std::string& name) {
230 RTC_CHECK(!dir.empty()) << "Special cases not implemented.";
231 return dir + kPathDelimiter + name;
232 }
233
GetFileSize(const std::string & filename)234 size_t GetFileSize(const std::string& filename) {
235 FILE* f = fopen(filename.c_str(), "rb");
236 size_t size = 0;
237 if (f != NULL) {
238 if (fseek(f, 0, SEEK_END) == 0) {
239 size = ftell(f);
240 }
241 fclose(f);
242 }
243 return size;
244 }
245
246 } // namespace test
247 } // namespace webrtc
248