summaryrefslogtreecommitdiff
path: root/src/common/file_util.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/file_util.cpp515
1 files changed, 223 insertions, 292 deletions
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index bc83ab737..c8723a4b3 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -2,73 +2,70 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/file_util.h"
5#include "common/assert.h" 6#include "common/assert.h"
6#include "common/common_funcs.h" 7#include "common/common_funcs.h"
7#include "common/common_paths.h" 8#include "common/common_paths.h"
8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10 10
11#ifdef _WIN32 11#ifdef _WIN32
12 #include <windows.h> 12#include <windows.h>
13 #include <shlobj.h> // for SHGetFolderPath 13#include <commdlg.h> // for GetSaveFileName
14 #include <shellapi.h> 14#include <direct.h> // getcwd
15 #include <commdlg.h> // for GetSaveFileName 15#include <io.h>
16 #include <io.h> 16#include <shellapi.h>
17 #include <direct.h> // getcwd 17#include <shlobj.h> // for SHGetFolderPath
18 #include <tchar.h> 18#include <tchar.h>
19 19
20 #include "common/string_util.h" 20#include "common/string_util.h"
21 21
22 // 64 bit offsets for windows 22// 64 bit offsets for windows
23 #define fseeko _fseeki64 23#define fseeko _fseeki64
24 #define ftello _ftelli64 24#define ftello _ftelli64
25 #define atoll _atoi64 25#define atoll _atoi64
26 #define stat64 _stat64 26#define stat64 _stat64
27 #define fstat64 _fstat64 27#define fstat64 _fstat64
28 #define fileno _fileno 28#define fileno _fileno
29#else 29#else
30 #ifdef __APPLE__ 30#ifdef __APPLE__
31 #include <sys/param.h> 31#include <sys/param.h>
32 #endif 32#endif
33 #include <cctype> 33#include <cctype>
34 #include <cerrno> 34#include <cerrno>
35 #include <cstdlib> 35#include <cstdlib>
36 #include <cstring> 36#include <cstring>
37 #include <dirent.h> 37#include <dirent.h>
38 #include <pwd.h> 38#include <pwd.h>
39 #include <unistd.h> 39#include <unistd.h>
40#endif 40#endif
41 41
42#if defined(__APPLE__) 42#if defined(__APPLE__)
43 #include <CoreFoundation/CFString.h> 43#include <CoreFoundation/CFBundle.h>
44 #include <CoreFoundation/CFURL.h> 44#include <CoreFoundation/CFString.h>
45 #include <CoreFoundation/CFBundle.h> 45#include <CoreFoundation/CFURL.h>
46#endif 46#endif
47 47
48#include <algorithm> 48#include <algorithm>
49#include <sys/stat.h> 49#include <sys/stat.h>
50 50
51#ifndef S_ISDIR 51#ifndef S_ISDIR
52 #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) 52#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
53#endif 53#endif
54 54
55#ifdef BSD4_4 55#ifdef BSD4_4
56 #define stat64 stat 56#define stat64 stat
57 #define fstat64 fstat 57#define fstat64 fstat
58#endif 58#endif
59 59
60// This namespace has various generic functions related to files and paths. 60// This namespace has various generic functions related to files and paths.
61// The code still needs a ton of cleanup. 61// The code still needs a ton of cleanup.
62// REMEMBER: strdup considered harmful! 62// REMEMBER: strdup considered harmful!
63namespace FileUtil 63namespace FileUtil {
64{
65 64
66// Remove any ending forward slashes from directory paths 65// Remove any ending forward slashes from directory paths
67// Modifies argument. 66// Modifies argument.
68static void StripTailDirSlashes(std::string &fname) 67static void StripTailDirSlashes(std::string& fname) {
69{ 68 if (fname.length() > 1) {
70 if (fname.length() > 1)
71 {
72 size_t i = fname.length(); 69 size_t i = fname.length();
73 while (i > 0 && fname[i - 1] == DIR_SEP_CHR) 70 while (i > 0 && fname[i - 1] == DIR_SEP_CHR)
74 --i; 71 --i;
@@ -78,8 +75,7 @@ static void StripTailDirSlashes(std::string &fname)
78} 75}
79 76
80// Returns true if file filename exists 77// Returns true if file filename exists
81bool Exists(const std::string &filename) 78bool Exists(const std::string& filename) {
82{
83 struct stat64 file_info; 79 struct stat64 file_info;
84 80
85 std::string copy(filename); 81 std::string copy(filename);
@@ -99,8 +95,7 @@ bool Exists(const std::string &filename)
99} 95}
100 96
101// Returns true if filename is a directory 97// Returns true if filename is a directory
102bool IsDirectory(const std::string &filename) 98bool IsDirectory(const std::string& filename) {
103{
104 struct stat64 file_info; 99 struct stat64 file_info;
105 100
106 std::string copy(filename); 101 std::string copy(filename);
@@ -117,8 +112,8 @@ bool IsDirectory(const std::string &filename)
117#endif 112#endif
118 113
119 if (result < 0) { 114 if (result < 0) {
120 LOG_WARNING(Common_Filesystem, "stat failed on %s: %s", 115 LOG_WARNING(Common_Filesystem, "stat failed on %s: %s", filename.c_str(),
121 filename.c_str(), GetLastErrorMsg()); 116 GetLastErrorMsg());
122 return false; 117 return false;
123 } 118 }
124 119
@@ -127,36 +122,32 @@ bool IsDirectory(const std::string &filename)
127 122
128// Deletes a given filename, return true on success 123// Deletes a given filename, return true on success
129// Doesn't supports deleting a directory 124// Doesn't supports deleting a directory
130bool Delete(const std::string &filename) 125bool Delete(const std::string& filename) {
131{
132 LOG_INFO(Common_Filesystem, "file %s", filename.c_str()); 126 LOG_INFO(Common_Filesystem, "file %s", filename.c_str());
133 127
134 // Return true because we care about the file no 128 // Return true because we care about the file no
135 // being there, not the actual delete. 129 // being there, not the actual delete.
136 if (!Exists(filename)) 130 if (!Exists(filename)) {
137 {
138 LOG_WARNING(Common_Filesystem, "%s does not exist", filename.c_str()); 131 LOG_WARNING(Common_Filesystem, "%s does not exist", filename.c_str());
139 return true; 132 return true;
140 } 133 }
141 134
142 // We can't delete a directory 135 // We can't delete a directory
143 if (IsDirectory(filename)) 136 if (IsDirectory(filename)) {
144 {
145 LOG_ERROR(Common_Filesystem, "Failed: %s is a directory", filename.c_str()); 137 LOG_ERROR(Common_Filesystem, "Failed: %s is a directory", filename.c_str());
146 return false; 138 return false;
147 } 139 }
148 140
149#ifdef _WIN32 141#ifdef _WIN32
150 if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) 142 if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) {
151 { 143 LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s", filename.c_str(),
152 LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s", 144 GetLastErrorMsg());
153 filename.c_str(), GetLastErrorMsg());
154 return false; 145 return false;
155 } 146 }
156#else 147#else
157 if (unlink(filename.c_str()) == -1) { 148 if (unlink(filename.c_str()) == -1) {
158 LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s", 149 LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s", filename.c_str(),
159 filename.c_str(), GetLastErrorMsg()); 150 GetLastErrorMsg());
160 return false; 151 return false;
161 } 152 }
162#endif 153#endif
@@ -165,16 +156,15 @@ bool Delete(const std::string &filename)
165} 156}
166 157
167// Returns true if successful, or path already exists. 158// Returns true if successful, or path already exists.
168bool CreateDir(const std::string &path) 159bool CreateDir(const std::string& path) {
169{
170 LOG_TRACE(Common_Filesystem, "directory %s", path.c_str()); 160 LOG_TRACE(Common_Filesystem, "directory %s", path.c_str());
171#ifdef _WIN32 161#ifdef _WIN32
172 if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr)) 162 if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr))
173 return true; 163 return true;
174 DWORD error = GetLastError(); 164 DWORD error = GetLastError();
175 if (error == ERROR_ALREADY_EXISTS) 165 if (error == ERROR_ALREADY_EXISTS) {
176 { 166 LOG_WARNING(Common_Filesystem, "CreateDirectory failed on %s: already exists",
177 LOG_WARNING(Common_Filesystem, "CreateDirectory failed on %s: already exists", path.c_str()); 167 path.c_str());
178 return true; 168 return true;
179 } 169 }
180 LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error); 170 LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error);
@@ -185,8 +175,7 @@ bool CreateDir(const std::string &path)
185 175
186 int err = errno; 176 int err = errno;
187 177
188 if (err == EEXIST) 178 if (err == EEXIST) {
189 {
190 LOG_WARNING(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str()); 179 LOG_WARNING(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str());
191 return true; 180 return true;
192 } 181 }
@@ -197,20 +186,17 @@ bool CreateDir(const std::string &path)
197} 186}
198 187
199// Creates the full path of fullPath returns true on success 188// Creates the full path of fullPath returns true on success
200bool CreateFullPath(const std::string &fullPath) 189bool CreateFullPath(const std::string& fullPath) {
201{
202 int panicCounter = 100; 190 int panicCounter = 100;
203 LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str()); 191 LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str());
204 192
205 if (FileUtil::Exists(fullPath)) 193 if (FileUtil::Exists(fullPath)) {
206 {
207 LOG_WARNING(Common_Filesystem, "path exists %s", fullPath.c_str()); 194 LOG_WARNING(Common_Filesystem, "path exists %s", fullPath.c_str());
208 return true; 195 return true;
209 } 196 }
210 197
211 size_t position = 0; 198 size_t position = 0;
212 while (true) 199 while (true) {
213 {
214 // Find next sub path 200 // Find next sub path
215 position = fullPath.find(DIR_SEP_CHR, position); 201 position = fullPath.find(DIR_SEP_CHR, position);
216 202
@@ -227,8 +213,7 @@ bool CreateFullPath(const std::string &fullPath)
227 213
228 // A safety check 214 // A safety check
229 panicCounter--; 215 panicCounter--;
230 if (panicCounter <= 0) 216 if (panicCounter <= 0) {
231 {
232 LOG_ERROR(Common, "CreateFullPath: directory structure is too deep"); 217 LOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
233 return false; 218 return false;
234 } 219 }
@@ -236,15 +221,12 @@ bool CreateFullPath(const std::string &fullPath)
236 } 221 }
237} 222}
238 223
239
240// Deletes a directory filename, returns true on success 224// Deletes a directory filename, returns true on success
241bool DeleteDir(const std::string &filename) 225bool DeleteDir(const std::string& filename) {
242{
243 LOG_INFO(Common_Filesystem, "directory %s", filename.c_str()); 226 LOG_INFO(Common_Filesystem, "directory %s", filename.c_str());
244 227
245 // check if a directory 228 // check if a directory
246 if (!FileUtil::IsDirectory(filename)) 229 if (!FileUtil::IsDirectory(filename)) {
247 {
248 LOG_ERROR(Common_Filesystem, "Not a directory %s", filename.c_str()); 230 LOG_ERROR(Common_Filesystem, "Not a directory %s", filename.c_str());
249 return false; 231 return false;
250 } 232 }
@@ -262,83 +244,73 @@ bool DeleteDir(const std::string &filename)
262} 244}
263 245
264// renames file srcFilename to destFilename, returns true on success 246// renames file srcFilename to destFilename, returns true on success
265bool Rename(const std::string &srcFilename, const std::string &destFilename) 247bool Rename(const std::string& srcFilename, const std::string& destFilename) {
266{ 248 LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str());
267 LOG_TRACE(Common_Filesystem, "%s --> %s",
268 srcFilename.c_str(), destFilename.c_str());
269#ifdef _WIN32 249#ifdef _WIN32
270 if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(), Common::UTF8ToUTF16W(destFilename).c_str()) == 0) 250 if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(),
251 Common::UTF8ToUTF16W(destFilename).c_str()) == 0)
271 return true; 252 return true;
272#else 253#else
273 if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) 254 if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
274 return true; 255 return true;
275#endif 256#endif
276 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", 257 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
277 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 258 GetLastErrorMsg());
278 return false; 259 return false;
279} 260}
280 261
281// copies file srcFilename to destFilename, returns true on success 262// copies file srcFilename to destFilename, returns true on success
282bool Copy(const std::string &srcFilename, const std::string &destFilename) 263bool Copy(const std::string& srcFilename, const std::string& destFilename) {
283{ 264 LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str());
284 LOG_TRACE(Common_Filesystem, "%s --> %s",
285 srcFilename.c_str(), destFilename.c_str());
286#ifdef _WIN32 265#ifdef _WIN32
287 if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(), Common::UTF8ToUTF16W(destFilename).c_str(), FALSE)) 266 if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(),
267 Common::UTF8ToUTF16W(destFilename).c_str(), FALSE))
288 return true; 268 return true;
289 269
290 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", 270 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
291 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 271 GetLastErrorMsg());
292 return false; 272 return false;
293#else 273#else
294 274
295 // buffer size 275// buffer size
296#define BSIZE 1024 276#define BSIZE 1024
297 277
298 char buffer[BSIZE]; 278 char buffer[BSIZE];
299 279
300 // Open input file 280 // Open input file
301 FILE *input = fopen(srcFilename.c_str(), "rb"); 281 FILE* input = fopen(srcFilename.c_str(), "rb");
302 if (!input) 282 if (!input) {
303 { 283 LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s", srcFilename.c_str(),
304 LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s", 284 destFilename.c_str(), GetLastErrorMsg());
305 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
306 return false; 285 return false;
307 } 286 }
308 287
309 // open output file 288 // open output file
310 FILE *output = fopen(destFilename.c_str(), "wb"); 289 FILE* output = fopen(destFilename.c_str(), "wb");
311 if (!output) 290 if (!output) {
312 {
313 fclose(input); 291 fclose(input);
314 LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s", 292 LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s", srcFilename.c_str(),
315 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 293 destFilename.c_str(), GetLastErrorMsg());
316 return false; 294 return false;
317 } 295 }
318 296
319 // copy loop 297 // copy loop
320 while (!feof(input)) 298 while (!feof(input)) {
321 {
322 // read input 299 // read input
323 int rnum = fread(buffer, sizeof(char), BSIZE, input); 300 int rnum = fread(buffer, sizeof(char), BSIZE, input);
324 if (rnum != BSIZE) 301 if (rnum != BSIZE) {
325 { 302 if (ferror(input) != 0) {
326 if (ferror(input) != 0) 303 LOG_ERROR(Common_Filesystem, "failed reading from source, %s --> %s: %s",
327 { 304 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
328 LOG_ERROR(Common_Filesystem,
329 "failed reading from source, %s --> %s: %s",
330 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
331 goto bail; 305 goto bail;
332 } 306 }
333 } 307 }
334 308
335 // write output 309 // write output
336 int wnum = fwrite(buffer, sizeof(char), rnum, output); 310 int wnum = fwrite(buffer, sizeof(char), rnum, output);
337 if (wnum != rnum) 311 if (wnum != rnum) {
338 { 312 LOG_ERROR(Common_Filesystem, "failed writing to output, %s --> %s: %s",
339 LOG_ERROR(Common_Filesystem, 313 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
340 "failed writing to output, %s --> %s: %s",
341 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
342 goto bail; 314 goto bail;
343 } 315 }
344 } 316 }
@@ -356,16 +328,13 @@ bail:
356} 328}
357 329
358// Returns the size of filename (64bit) 330// Returns the size of filename (64bit)
359u64 GetSize(const std::string &filename) 331u64 GetSize(const std::string& filename) {
360{ 332 if (!Exists(filename)) {
361 if (!Exists(filename))
362 {
363 LOG_ERROR(Common_Filesystem, "failed %s: No such file", filename.c_str()); 333 LOG_ERROR(Common_Filesystem, "failed %s: No such file", filename.c_str());
364 return 0; 334 return 0;
365 } 335 }
366 336
367 if (IsDirectory(filename)) 337 if (IsDirectory(filename)) {
368 {
369 LOG_ERROR(Common_Filesystem, "failed %s: is a directory", filename.c_str()); 338 LOG_ERROR(Common_Filesystem, "failed %s: is a directory", filename.c_str());
370 return 0; 339 return 0;
371 } 340 }
@@ -377,65 +346,54 @@ u64 GetSize(const std::string &filename)
377 if (stat64(filename.c_str(), &buf) == 0) 346 if (stat64(filename.c_str(), &buf) == 0)
378#endif 347#endif
379 { 348 {
380 LOG_TRACE(Common_Filesystem, "%s: %lld", 349 LOG_TRACE(Common_Filesystem, "%s: %lld", filename.c_str(), (long long)buf.st_size);
381 filename.c_str(), (long long)buf.st_size);
382 return buf.st_size; 350 return buf.st_size;
383 } 351 }
384 352
385 LOG_ERROR(Common_Filesystem, "Stat failed %s: %s", 353 LOG_ERROR(Common_Filesystem, "Stat failed %s: %s", filename.c_str(), GetLastErrorMsg());
386 filename.c_str(), GetLastErrorMsg());
387 return 0; 354 return 0;
388} 355}
389 356
390// Overloaded GetSize, accepts file descriptor 357// Overloaded GetSize, accepts file descriptor
391u64 GetSize(const int fd) 358u64 GetSize(const int fd) {
392{
393 struct stat64 buf; 359 struct stat64 buf;
394 if (fstat64(fd, &buf) != 0) { 360 if (fstat64(fd, &buf) != 0) {
395 LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s", 361 LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s", fd, GetLastErrorMsg());
396 fd, GetLastErrorMsg());
397 return 0; 362 return 0;
398 } 363 }
399 return buf.st_size; 364 return buf.st_size;
400} 365}
401 366
402// Overloaded GetSize, accepts FILE* 367// Overloaded GetSize, accepts FILE*
403u64 GetSize(FILE *f) 368u64 GetSize(FILE* f) {
404{
405 // can't use off_t here because it can be 32-bit 369 // can't use off_t here because it can be 32-bit
406 u64 pos = ftello(f); 370 u64 pos = ftello(f);
407 if (fseeko(f, 0, SEEK_END) != 0) { 371 if (fseeko(f, 0, SEEK_END) != 0) {
408 LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", 372 LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg());
409 f, GetLastErrorMsg());
410 return 0; 373 return 0;
411 } 374 }
412 u64 size = ftello(f); 375 u64 size = ftello(f);
413 if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { 376 if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
414 LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", 377 LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg());
415 f, GetLastErrorMsg());
416 return 0; 378 return 0;
417 } 379 }
418 return size; 380 return size;
419} 381}
420 382
421// creates an empty file filename, returns true on success 383// creates an empty file filename, returns true on success
422bool CreateEmptyFile(const std::string &filename) 384bool CreateEmptyFile(const std::string& filename) {
423{
424 LOG_TRACE(Common_Filesystem, "%s", filename.c_str()); 385 LOG_TRACE(Common_Filesystem, "%s", filename.c_str());
425 386
426 if (!FileUtil::IOFile(filename, "wb")) 387 if (!FileUtil::IOFile(filename, "wb")) {
427 { 388 LOG_ERROR(Common_Filesystem, "failed %s: %s", filename.c_str(), GetLastErrorMsg());
428 LOG_ERROR(Common_Filesystem, "failed %s: %s",
429 filename.c_str(), GetLastErrorMsg());
430 return false; 389 return false;
431 } 390 }
432 391
433 return true; 392 return true;
434} 393}
435 394
436 395bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory,
437bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback) 396 DirectoryEntryCallable callback) {
438{
439 LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str()); 397 LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str());
440 398
441 // How many files + directories we found 399 // How many files + directories we found
@@ -457,7 +415,7 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
457 do { 415 do {
458 const std::string virtual_name(Common::UTF16ToUTF8(ffd.cFileName)); 416 const std::string virtual_name(Common::UTF16ToUTF8(ffd.cFileName));
459#else 417#else
460 DIR *dirp = opendir(directory.c_str()); 418 DIR* dirp = opendir(directory.c_str());
461 if (!dirp) 419 if (!dirp)
462 return false; 420 return false;
463 421
@@ -493,8 +451,8 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
493 return true; 451 return true;
494} 452}
495 453
496unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion) 454unsigned ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
497{ 455 unsigned int recursion) {
498 const auto callback = [recursion, &parent_entry](unsigned* num_entries_out, 456 const auto callback = [recursion, &parent_entry](unsigned* num_entries_out,
499 const std::string& directory, 457 const std::string& directory,
500 const std::string& virtual_name) -> bool { 458 const std::string& virtual_name) -> bool {
@@ -526,11 +484,8 @@ unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry,
526 return ForeachDirectoryEntry(&num_entries, directory, callback) ? num_entries : 0; 484 return ForeachDirectoryEntry(&num_entries, directory, callback) ? num_entries : 0;
527} 485}
528 486
529 487bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) {
530bool DeleteDirRecursively(const std::string &directory, unsigned int recursion) 488 const auto callback = [recursion](unsigned* num_entries_out, const std::string& directory,
531{
532 const auto callback = [recursion](unsigned* num_entries_out,
533 const std::string& directory,
534 const std::string& virtual_name) -> bool { 489 const std::string& virtual_name) -> bool {
535 std::string new_path = directory + DIR_SEP_CHR + virtual_name; 490 std::string new_path = directory + DIR_SEP_CHR + virtual_name;
536 491
@@ -551,53 +506,53 @@ bool DeleteDirRecursively(const std::string &directory, unsigned int recursion)
551} 506}
552 507
553// Create directory and copy contents (does not overwrite existing files) 508// Create directory and copy contents (does not overwrite existing files)
554void CopyDir(const std::string &source_path, const std::string &dest_path) 509void CopyDir(const std::string& source_path, const std::string& dest_path) {
555{
556#ifndef _WIN32 510#ifndef _WIN32
557 if (source_path == dest_path) return; 511 if (source_path == dest_path)
558 if (!FileUtil::Exists(source_path)) return; 512 return;
559 if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path); 513 if (!FileUtil::Exists(source_path))
560 514 return;
561 DIR *dirp = opendir(source_path.c_str()); 515 if (!FileUtil::Exists(dest_path))
562 if (!dirp) return; 516 FileUtil::CreateFullPath(dest_path);
517
518 DIR* dirp = opendir(source_path.c_str());
519 if (!dirp)
520 return;
563 521
564 while (struct dirent* result = readdir(dirp)) { 522 while (struct dirent* result = readdir(dirp)) {
565 const std::string virtualName(result->d_name); 523 const std::string virtualName(result->d_name);
566 // check for "." and ".." 524 // check for "." and ".."
567 if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || 525 if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
568 ((virtualName[0] == '.') && (virtualName[1] == '.') && 526 ((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0')))
569 (virtualName[2] == '\0')))
570 continue; 527 continue;
571 528
572 std::string source, dest; 529 std::string source, dest;
573 source = source_path + virtualName; 530 source = source_path + virtualName;
574 dest = dest_path + virtualName; 531 dest = dest_path + virtualName;
575 if (IsDirectory(source)) 532 if (IsDirectory(source)) {
576 {
577 source += '/'; 533 source += '/';
578 dest += '/'; 534 dest += '/';
579 if (!FileUtil::Exists(dest)) FileUtil::CreateFullPath(dest); 535 if (!FileUtil::Exists(dest))
536 FileUtil::CreateFullPath(dest);
580 CopyDir(source, dest); 537 CopyDir(source, dest);
581 } 538 } else if (!FileUtil::Exists(dest))
582 else if (!FileUtil::Exists(dest)) FileUtil::Copy(source, dest); 539 FileUtil::Copy(source, dest);
583 } 540 }
584 closedir(dirp); 541 closedir(dirp);
585#endif 542#endif
586} 543}
587 544
588// Returns the current directory 545// Returns the current directory
589std::string GetCurrentDir() 546std::string GetCurrentDir() {
590{ 547// Get the current working directory (getcwd uses malloc)
591 // Get the current working directory (getcwd uses malloc)
592#ifdef _WIN32 548#ifdef _WIN32
593 wchar_t *dir; 549 wchar_t* dir;
594 if (!(dir = _wgetcwd(nullptr, 0))) { 550 if (!(dir = _wgetcwd(nullptr, 0))) {
595#else 551#else
596 char *dir; 552 char* dir;
597 if (!(dir = getcwd(nullptr, 0))) { 553 if (!(dir = getcwd(nullptr, 0))) {
598#endif 554#endif
599 LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s", 555 LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s", GetLastErrorMsg());
600 GetLastErrorMsg());
601 return nullptr; 556 return nullptr;
602 } 557 }
603#ifdef _WIN32 558#ifdef _WIN32
@@ -610,8 +565,7 @@ std::string GetCurrentDir()
610} 565}
611 566
612// Sets the current directory to the given directory 567// Sets the current directory to the given directory
613bool SetCurrentDir(const std::string &directory) 568bool SetCurrentDir(const std::string& directory) {
614{
615#ifdef _WIN32 569#ifdef _WIN32
616 return _wchdir(Common::UTF8ToUTF16W(directory).c_str()) == 0; 570 return _wchdir(Common::UTF8ToUTF16W(directory).c_str()) == 0;
617#else 571#else
@@ -620,8 +574,7 @@ bool SetCurrentDir(const std::string &directory)
620} 574}
621 575
622#if defined(__APPLE__) 576#if defined(__APPLE__)
623std::string GetBundleDirectory() 577std::string GetBundleDirectory() {
624{
625 CFURLRef BundleRef; 578 CFURLRef BundleRef;
626 char AppBundlePath[MAXPATHLEN]; 579 char AppBundlePath[MAXPATHLEN];
627 // Get the main bundle for the app 580 // Get the main bundle for the app
@@ -636,11 +589,9 @@ std::string GetBundleDirectory()
636#endif 589#endif
637 590
638#ifdef _WIN32 591#ifdef _WIN32
639std::string& GetExeDirectory() 592std::string& GetExeDirectory() {
640{
641 static std::string exe_path; 593 static std::string exe_path;
642 if (exe_path.empty()) 594 if (exe_path.empty()) {
643 {
644 wchar_t wchar_exe_path[2048]; 595 wchar_t wchar_exe_path[2048];
645 GetModuleFileNameW(nullptr, wchar_exe_path, 2048); 596 GetModuleFileNameW(nullptr, wchar_exe_path, 2048);
646 exe_path = Common::UTF16ToUTF8(wchar_exe_path); 597 exe_path = Common::UTF16ToUTF8(wchar_exe_path);
@@ -660,7 +611,8 @@ static const std::string& GetHomeDirectory() {
660 home_path = envvar; 611 home_path = envvar;
661 } else { 612 } else {
662 auto pw = getpwuid(getuid()); 613 auto pw = getpwuid(getuid());
663 ASSERT_MSG(pw, "$HOME isn’t defined, and the current user can’t be found in /etc/passwd."); 614 ASSERT_MSG(pw,
615 "$HOME isn’t defined, and the current user can’t be found in /etc/passwd.");
664 home_path = pw->pw_dir; 616 home_path = pw->pw_dir;
665 } 617 }
666 } 618 }
@@ -699,11 +651,10 @@ static const std::string GetUserDirectory(const std::string& envvar) {
699} 651}
700#endif 652#endif
701 653
702std::string GetSysDirectory() 654std::string GetSysDirectory() {
703{
704 std::string sysDir; 655 std::string sysDir;
705 656
706#if defined (__APPLE__) 657#if defined(__APPLE__)
707 sysDir = GetBundleDirectory(); 658 sysDir = GetBundleDirectory();
708 sysDir += DIR_SEP; 659 sysDir += DIR_SEP;
709 sysDir += SYSDATA_DIR; 660 sysDir += SYSDATA_DIR;
@@ -718,123 +669,114 @@ std::string GetSysDirectory()
718 669
719// Returns a string with a Citra data dir or file in the user's home 670// Returns a string with a Citra data dir or file in the user's home
720// directory. To be used in "multi-user" mode (that is, installed). 671// directory. To be used in "multi-user" mode (that is, installed).
721const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) 672const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath) {
722{
723 static std::string paths[NUM_PATH_INDICES]; 673 static std::string paths[NUM_PATH_INDICES];
724 674
725 // Set up all paths and files on the first run 675 // Set up all paths and files on the first run
726 if (paths[D_USER_IDX].empty()) 676 if (paths[D_USER_IDX].empty()) {
727 {
728#ifdef _WIN32 677#ifdef _WIN32
729 paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; 678 paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
730 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; 679 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
731 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; 680 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
732#else 681#else
733 if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) { 682 if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
734 paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; 683 paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
735 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; 684 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
736 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; 685 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
737 } else { 686 } else {
738 std::string data_dir = GetUserDirectory("XDG_DATA_HOME"); 687 std::string data_dir = GetUserDirectory("XDG_DATA_HOME");
739 std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME"); 688 std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME");
740 std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME"); 689 std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME");
741 690
742 paths[D_USER_IDX] = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; 691 paths[D_USER_IDX] = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
743 paths[D_CONFIG_IDX] = config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; 692 paths[D_CONFIG_IDX] = config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
744 paths[D_CACHE_IDX] = cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP; 693 paths[D_CACHE_IDX] = cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
745 } 694 }
746#endif 695#endif
747 696
748 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; 697 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
749 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; 698 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
750 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; 699 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
751 paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP; 700 paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
752 paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP; 701 paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
753 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; 702 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
754 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; 703 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
755 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; 704 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
756 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; 705 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
757 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; 706 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
758 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; 707 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
759 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; 708 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
760 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; 709 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
761 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; 710 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
762 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; 711 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
763 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; 712 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
764 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; 713 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
765 } 714 }
766 715
767 if (!newPath.empty()) 716 if (!newPath.empty()) {
768 { 717 if (!FileUtil::IsDirectory(newPath)) {
769 if (!FileUtil::IsDirectory(newPath))
770 {
771 LOG_ERROR(Common_Filesystem, "Invalid path specified %s", newPath.c_str()); 718 LOG_ERROR(Common_Filesystem, "Invalid path specified %s", newPath.c_str());
772 return paths[DirIDX]; 719 return paths[DirIDX];
773 } 720 } else {
774 else
775 {
776 paths[DirIDX] = newPath; 721 paths[DirIDX] = newPath;
777 } 722 }
778 723
779 switch (DirIDX) 724 switch (DirIDX) {
780 {
781 case D_ROOT_IDX: 725 case D_ROOT_IDX:
782 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; 726 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
783 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; 727 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP;
784 paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; 728 paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF;
785 break; 729 break;
786 730
787 case D_USER_IDX: 731 case D_USER_IDX:
788 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; 732 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
789 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; 733 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
790 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; 734 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
791 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; 735 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
792 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; 736 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
793 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; 737 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
794 paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP; 738 paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
795 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; 739 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
796 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; 740 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
797 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; 741 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
798 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; 742 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
799 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; 743 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
800 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; 744 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
801 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; 745 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
802 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; 746 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
803 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; 747 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
804 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; 748 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP;
805 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; 749 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
806 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; 750 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
807 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; 751 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
808 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; 752 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
809 break; 753 break;
810 754
811 case D_CONFIG_IDX: 755 case D_CONFIG_IDX:
812 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; 756 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
813 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; 757 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
814 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; 758 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
815 break; 759 break;
816 760
817 case D_DUMP_IDX: 761 case D_DUMP_IDX:
818 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; 762 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
819 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; 763 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
820 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; 764 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
821 break; 765 break;
822 766
823 case D_LOGS_IDX: 767 case D_LOGS_IDX:
824 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; 768 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
825 } 769 }
826 } 770 }
827 771
828 return paths[DirIDX]; 772 return paths[DirIDX];
829} 773}
830 774
831size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename) 775size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) {
832{
833 return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); 776 return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
834} 777}
835 778
836size_t ReadFileToString(bool text_file, const char *filename, std::string &str) 779size_t ReadFileToString(bool text_file, const char* filename, std::string& str) {
837{
838 IOFile file(filename, text_file ? "r" : "rb"); 780 IOFile file(filename, text_file ? "r" : "rb");
839 781
840 if (!file) 782 if (!file)
@@ -886,42 +828,36 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
886 } 828 }
887} 829}
888 830
889IOFile::IOFile() 831IOFile::IOFile() {
890{
891} 832}
892 833
893IOFile::IOFile(const std::string& filename, const char openmode[]) 834IOFile::IOFile(const std::string& filename, const char openmode[]) {
894{
895 Open(filename, openmode); 835 Open(filename, openmode);
896} 836}
897 837
898IOFile::~IOFile() 838IOFile::~IOFile() {
899{
900 Close(); 839 Close();
901} 840}
902 841
903IOFile::IOFile(IOFile&& other) 842IOFile::IOFile(IOFile&& other) {
904{
905 Swap(other); 843 Swap(other);
906} 844}
907 845
908IOFile& IOFile::operator=(IOFile&& other) 846IOFile& IOFile::operator=(IOFile&& other) {
909{
910 Swap(other); 847 Swap(other);
911 return *this; 848 return *this;
912} 849}
913 850
914void IOFile::Swap(IOFile& other) 851void IOFile::Swap(IOFile& other) {
915{
916 std::swap(m_file, other.m_file); 852 std::swap(m_file, other.m_file);
917 std::swap(m_good, other.m_good); 853 std::swap(m_good, other.m_good);
918} 854}
919 855
920bool IOFile::Open(const std::string& filename, const char openmode[]) 856bool IOFile::Open(const std::string& filename, const char openmode[]) {
921{
922 Close(); 857 Close();
923#ifdef _WIN32 858#ifdef _WIN32
924 _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), Common::UTF8ToUTF16W(openmode).c_str()); 859 _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(),
860 Common::UTF8ToUTF16W(openmode).c_str());
925#else 861#else
926 m_file = fopen(filename.c_str(), openmode); 862 m_file = fopen(filename.c_str(), openmode);
927#endif 863#endif
@@ -930,8 +866,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
930 return m_good; 866 return m_good;
931} 867}
932 868
933bool IOFile::Close() 869bool IOFile::Close() {
934{
935 if (!IsOpen() || 0 != std::fclose(m_file)) 870 if (!IsOpen() || 0 != std::fclose(m_file))
936 m_good = false; 871 m_good = false;
937 872
@@ -939,50 +874,46 @@ bool IOFile::Close()
939 return m_good; 874 return m_good;
940} 875}
941 876
942u64 IOFile::GetSize() const 877u64 IOFile::GetSize() const {
943{
944 if (IsOpen()) 878 if (IsOpen())
945 return FileUtil::GetSize(m_file); 879 return FileUtil::GetSize(m_file);
946 880
947 return 0; 881 return 0;
948} 882}
949 883
950bool IOFile::Seek(s64 off, int origin) 884bool IOFile::Seek(s64 off, int origin) {
951{
952 if (!IsOpen() || 0 != fseeko(m_file, off, origin)) 885 if (!IsOpen() || 0 != fseeko(m_file, off, origin))
953 m_good = false; 886 m_good = false;
954 887
955 return m_good; 888 return m_good;
956} 889}
957 890
958u64 IOFile::Tell() const 891u64 IOFile::Tell() const {
959{
960 if (IsOpen()) 892 if (IsOpen())
961 return ftello(m_file); 893 return ftello(m_file);
962 894
963 return -1; 895 return -1;
964} 896}
965 897
966bool IOFile::Flush() 898bool IOFile::Flush() {
967{
968 if (!IsOpen() || 0 != std::fflush(m_file)) 899 if (!IsOpen() || 0 != std::fflush(m_file))
969 m_good = false; 900 m_good = false;
970 901
971 return m_good; 902 return m_good;
972} 903}
973 904
974bool IOFile::Resize(u64 size) 905bool IOFile::Resize(u64 size) {
975{ 906 if (!IsOpen() ||
976 if (!IsOpen() || 0 != 907 0 !=
977#ifdef _WIN32 908#ifdef _WIN32
978 // ector: _chsize sucks, not 64-bit safe 909 // ector: _chsize sucks, not 64-bit safe
979 // F|RES: changed to _chsize_s. i think it is 64-bit safe 910 // F|RES: changed to _chsize_s. i think it is 64-bit safe
980 _chsize_s(_fileno(m_file), size) 911 _chsize_s(_fileno(m_file), size)
981#else 912#else
982 // TODO: handle 64bit and growing 913 // TODO: handle 64bit and growing
983 ftruncate(fileno(m_file), size) 914 ftruncate(fileno(m_file), size)
984#endif 915#endif
985 ) 916 )
986 m_good = false; 917 m_good = false;
987 918
988 return m_good; 919 return m_good;