Пример #1
0
// renames file srcFilename to destFilename, returns true on success
bool Rename(const std::string &srcFilename, const std::string &destFilename)
{
	INFO_LOG(COMMON, "Rename: %s --> %s",
			srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
	auto sf = UTF8ToTStr(srcFilename);
	auto df = UTF8ToTStr(destFilename);
	// The Internet seems torn about whether ReplaceFile is atomic or not.
	// Hopefully it's atomic enough...
	if (ReplaceFile(df.c_str(), sf.c_str(), nullptr, REPLACEFILE_IGNORE_MERGE_ERRORS, nullptr, nullptr))
		return true;
	// Might have failed because the destination doesn't exist.
	if (GetLastError() == ERROR_FILE_NOT_FOUND)
	{
		if (MoveFile(sf.c_str(), df.c_str()))
			return true;
	}
#else
	if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
		return true;
#endif
	ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s",
			  srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
	return false;
}
Пример #2
0
bool IOFile::Open(const std::string& filename, const char openmode[])
{
	Close();
#ifdef _WIN32
	_tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str());
#else
	m_file = fopen(filename.c_str(), openmode);
#endif

	m_good = IsOpen();
	return m_good;
}
Пример #3
0
// Default non library dependent panic alert
bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style)
{
#ifdef _WIN32
    int STYLE = MB_ICONINFORMATION;
    if (Style == QUESTION) STYLE = MB_ICONQUESTION;
    if (Style == WARNING) STYLE = MB_ICONWARNING;

    return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(), STYLE | (yes_no ? MB_YESNO : MB_OK));
#else
    printf("%s\n", text);
    return true;
#endif
}
Пример #4
0
// Returns true if successful, or path already exists.
bool CreateDir(const std::string &path)
{
	INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
#ifdef _WIN32
	if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL))
		return true;
	DWORD error = GetLastError();
	if (error == ERROR_ALREADY_EXISTS)
	{
		WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str());
		return true;
	}
	ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error);
	return false;
#else
	if (mkdir(path.c_str(), 0755) == 0)
		return true;

	int err = errno;

	if (err == EEXIST)
	{
		WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str());
		return true;
	}

	ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err));
	return false;
#endif
}
Пример #5
0
// Returns the size of filename (64bit)
u64 GetSize(const std::string &filename)
{
	if (!Exists(filename))
	{
		WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str());
		return 0;
	}

	if (IsDirectory(filename))
	{
		WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str());
		return 0;
	}
	
	struct stat64 buf;
#ifdef _WIN32
	if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0)
#else
	if (stat64(filename.c_str(), &buf) == 0)
#endif
	{
		DEBUG_LOG(COMMON, "GetSize: %s: %lld",
				filename.c_str(), (long long)buf.st_size);
		return buf.st_size;
	}

	ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s",
			filename.c_str(), GetLastErrorMsg());
	return 0;
}
Пример #6
0
// Deletes a directory filename, returns true on success
bool DeleteDir(const std::string& filename)
{
  INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str());

  // check if a directory
  if (!IsDirectory(filename))
  {
    ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str());
    return false;
  }

#ifdef _WIN32
  if (::RemoveDirectory(UTF8ToTStr(filename).c_str()))
    return true;
  ERROR_LOG(COMMON, "DeleteDir: RemoveDirectory failed on %s: %s", filename.c_str(),
            GetLastErrorString().c_str());
#else
  if (rmdir(filename.c_str()) == 0)
    return true;
  ERROR_LOG(COMMON, "DeleteDir: rmdir failed on %s: %s", filename.c_str(),
            LastStrerrorString().c_str());
#endif

  return false;
}
Пример #7
0
void MemArena::GrabSHMSegment(size_t size)
{
#ifdef _WIN32
  const std::string name = "dolphin-emu." + std::to_string(GetCurrentProcessId());
  hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0,
                                     static_cast<DWORD>(size), UTF8ToTStr(name).c_str());
#elif defined(ANDROID)
  fd = AshmemCreateFileMapping(("dolphin-emu." + std::to_string(getpid())).c_str(), size);
  if (fd < 0)
  {
    NOTICE_LOG(MEMMAP, "Ashmem allocation failed");
    return;
  }
#else
  const std::string file_name = "/dolphin-emu." + std::to_string(getpid());
  fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
  if (fd == -1)
  {
    ERROR_LOG(MEMMAP, "shm_open failed: %s", strerror(errno));
    return;
  }
  shm_unlink(file_name.c_str());
  if (ftruncate(fd, size) < 0)
    ERROR_LOG(MEMMAP, "Failed to allocate low memory space");
#endif
}
Пример #8
0
// Create directory and copy contents (does not overwrite existing files)
void CopyDir(const std::string& source_path, const std::string& dest_path, bool destructive)
{
  if (source_path == dest_path)
    return;
  if (!Exists(source_path))
    return;
  if (!Exists(dest_path))
    File::CreateFullPath(dest_path);

#ifdef _WIN32
  WIN32_FIND_DATA ffd;
  HANDLE hFind = FindFirstFile(UTF8ToTStr(source_path + "\\*").c_str(), &ffd);

  if (hFind == INVALID_HANDLE_VALUE)
  {
    FindClose(hFind);
    return;
  }

  do
  {
    const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
  DIR* dirp = opendir(source_path.c_str());
  if (!dirp)
    return;

  while (dirent* result = readdir(dirp))
  {
    const std::string virtualName(result->d_name);
#endif
    // check for "." and ".."
    if (virtualName == "." || virtualName == "..")
      continue;

    std::string source = source_path + DIR_SEP + virtualName;
    std::string dest = dest_path + DIR_SEP + virtualName;
    if (IsDirectory(source))
    {
      if (!Exists(dest))
        File::CreateFullPath(dest + DIR_SEP);
      CopyDir(source, dest, destructive);
    }
    else if (!destructive && !Exists(dest))
    {
      Copy(source, dest);
    }
    else if (destructive)
    {
      Rename(source, dest);
    }
#ifdef _WIN32
  } while (FindNextFile(hFind, &ffd) != 0);
  FindClose(hFind);
#else
  }
  closedir(dirp);
#endif
}
Пример #9
0
// copies file source_path to destination_path, returns true on success
bool Copy(const std::string& source_path, const std::string& destination_path)
{
  INFO_LOG(COMMON, "Copy: %s --> %s", source_path.c_str(), destination_path.c_str());
#ifdef _WIN32
  if (CopyFile(UTF8ToTStr(source_path).c_str(), UTF8ToTStr(destination_path).c_str(), FALSE))
    return true;

  ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", source_path.c_str(), destination_path.c_str(),
            GetLastErrorString().c_str());
  return false;
#else
  std::ifstream source{source_path, std::ios::binary};
  std::ofstream destination{destination_path, std::ios::binary};
  destination << source.rdbuf();
  return source.good() && destination.good();
#endif
}
Пример #10
0
// Default non library dependent panic alert
bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int Style)
{
#ifdef _WIN32
  int STYLE = MB_ICONINFORMATION;
  if (Style == QUESTION)
    STYLE = MB_ICONQUESTION;
  if (Style == WARNING)
    STYLE = MB_ICONWARNING;

  return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(),
                             STYLE | (yes_no ? MB_YESNO : MB_OK));
#else
  fprintf(stderr, "%s\n", text);

  // Return no to any question (which will in general crash the emulator)
  return false;
#endif
}
Пример #11
0
// Create directory and copy contents (does not overwrite existing files)
void CopyDir(const std::string &source_path, const std::string &dest_path)
{
    if (source_path == dest_path) return;
    if (!File::Exists(source_path)) return;
    if (!File::Exists(dest_path)) File::CreateFullPath(dest_path);

#ifdef _WIN32
    WIN32_FIND_DATA ffd;
    HANDLE hFind = FindFirstFile(UTF8ToTStr(source_path + "\\*").c_str(), &ffd);

    if (hFind == INVALID_HANDLE_VALUE)
    {
        FindClose(hFind);
        return;
    }

    do
    {
        const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
    struct dirent dirent, *result = NULL;
    DIR *dirp = opendir(source_path.c_str());
    if (!dirp) return;

    while (!readdir_r(dirp, &dirent, &result) && result)
    {
        const std::string virtualName(result->d_name);
#endif
        // check for "." and ".."
        if (virtualName == "." || virtualName == "..")
            continue;

        std::string source, dest;
        source = source_path + virtualName;
        dest = dest_path + virtualName;
        if (IsDirectory(source))
        {
            source += '/';
            dest += '/';
            if (!File::Exists(dest)) File::CreateFullPath(dest);
            CopyDir(source, dest);
        }
        else if (!File::Exists(dest)) File::Copy(source, dest);
#ifdef _WIN32
    }
    while (FindNextFile(hFind, &ffd) != 0);
    FindClose(hFind);
#else
    }
    closedir(dirp);
#endif
}
Пример #12
0
std::string GetTempFilenameForAtomicWrite(const std::string &path)
{
	std::string abs = path;
#ifdef _WIN32
	TCHAR absbuf[MAX_PATH];
	if (_tfullpath(absbuf, UTF8ToTStr(path).c_str(), MAX_PATH) != nullptr)
		abs = TStrToUTF8(absbuf);
#else
	char absbuf[PATH_MAX];
	if (realpath(path.c_str(), absbuf) != nullptr)
		abs = absbuf;
#endif
	return abs + ".xxx";
}
Пример #13
0
bool RenameSync(const std::string &srcFilename, const std::string &destFilename)
{
	if (!Rename(srcFilename, destFilename))
		return false;
#ifdef _WIN32
	int fd = _topen(UTF8ToTStr(srcFilename).c_str(), _O_RDONLY);
	if (fd != -1)
	{
		_commit(fd);
		close(fd);
	}
#else
	char *path = strdup(srcFilename.c_str());
	FSyncPath(path);
	FSyncPath(dirname(path));
	free(path);
	path = strdup(destFilename.c_str());
	FSyncPath(dirname(path));
	free(path);
#endif
	return true;
}
Пример #14
0
// Deletes a given filename, return true on success
// Doesn't supports deleting a directory
bool Delete(const std::string& filename)
{
  INFO_LOG(COMMON, "Delete: file %s", filename.c_str());

  const FileInfo file_info(filename);

  // Return true because we care about the file no
  // being there, not the actual delete.
  if (!file_info.Exists())
  {
    WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str());
    return true;
  }

  // We can't delete a directory
  if (file_info.IsDirectory())
  {
    WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str());
    return false;
  }

#ifdef _WIN32
  if (!DeleteFile(UTF8ToTStr(filename).c_str()))
  {
    WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(),
             GetLastErrorMsg().c_str());
    return false;
  }
#else
  if (unlink(filename.c_str()) == -1)
  {
    WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", filename.c_str(),
             GetLastErrorMsg().c_str());
    return false;
  }
#endif

  return true;
}
Пример #15
0
// 100, 100, "Dolphin Log Console"
// Open console window - width and height is the size of console window
// Name is the window title
void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title)
{
#ifdef _WIN32
	if (!GetConsoleWindow())
	{
		// Open the console window and create the window handle for GetStdHandle()
		AllocConsole();
		// Hide
		if (Hidden) ShowWindow(GetConsoleWindow(), SW_HIDE);
		// Save the window handle that AllocConsole() created
		hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
		// Set the console window title
		SetConsoleTitle(UTF8ToTStr(Title).c_str());
		// Set letter space
		LetterSpace(80, 4000);
		//MoveWindow(GetConsoleWindow(), 200,200, 800,800, true);
	}
	else
	{
		hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
	}
#endif
}
Пример #16
0
// Deletes the given directory and anything under it. Returns true on success.
bool DeleteDirRecursively(const std::string &directory)
{
	INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str());
#ifdef _WIN32
	// Find the first file in the directory.
	WIN32_FIND_DATA ffd;
	HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd);

	if (hFind == INVALID_HANDLE_VALUE)
	{
		FindClose(hFind);
		return false;
	}

	// windows loop
	do
	{
		const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
	struct dirent dirent, *result = NULL;
	DIR *dirp = opendir(directory.c_str());
	if (!dirp)
		return false;

	// non windows loop
	while (!readdir_r(dirp, &dirent, &result) && result)
	{
		const std::string virtualName = result->d_name;
#endif

		// check for "." and ".."
		if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
			((virtualName[0] == '.') && (virtualName[1] == '.') && 
			 (virtualName[2] == '\0')))
			continue;

		std::string newPath = directory + DIR_SEP_CHR + virtualName;
		if (IsDirectory(newPath))
		{
			if (!DeleteDirRecursively(newPath))
			{
				#ifndef _WIN32
				closedir(dirp);
				#endif

				return false;
			}
		}
		else
		{
			if (!File::Delete(newPath))
			{
				#ifndef _WIN32
				closedir(dirp);
				#endif

				return false;
			}
		}

#ifdef _WIN32
	} while (FindNextFile(hFind, &ffd) != 0);
	FindClose(hFind);
#else
	}
	closedir(dirp);
#endif
	File::DeleteDir(directory);
		
	return true;
}
Пример #17
0
// Scans the directory tree gets, starting from _Directory and adds the
// results into parentEntry. Returns the number of files+directories found
u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
{
	INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str());
	// How many files + directories we found
	u32 foundEntries = 0;
#ifdef _WIN32
	// Find the first file in the directory.
	WIN32_FIND_DATA ffd;

	HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		FindClose(hFind);
		return foundEntries;
	}
	// windows loop
	do
	{
		FSTEntry entry;
		const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
	struct dirent dirent, *result = NULL;

	DIR *dirp = opendir(directory.c_str());
	if (!dirp)
		return 0;

	// non windows loop
	while (!readdir_r(dirp, &dirent, &result) && result)
	{
		FSTEntry entry;
		const std::string virtualName(result->d_name);
#endif
		// check for "." and ".."
		if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
				((virtualName[0] == '.') && (virtualName[1] == '.') && 
				 (virtualName[2] == '\0')))
			continue;
		entry.virtualName = virtualName;
		entry.physicalName = directory;
		entry.physicalName += DIR_SEP + entry.virtualName;

		if (IsDirectory(entry.physicalName.c_str()))
		{
			entry.isDirectory = true;
			// is a directory, lets go inside
			entry.size = ScanDirectoryTree(entry.physicalName, entry);
			foundEntries += (u32)entry.size;
		}
		else
		{ // is a file 
			entry.isDirectory = false;
			entry.size = GetSize(entry.physicalName.c_str());
		}
		++foundEntries;
		// Push into the tree
		parentEntry.children.push_back(entry);		
#ifdef _WIN32 
	} while (FindNextFile(hFind, &ffd) != 0);
	FindClose(hFind);
#else
	}
	closedir(dirp);
#endif
	// Return number of entries found.
	return foundEntries;
}
Пример #18
0
// copies file srcFilename to destFilename, returns true on success 
bool Copy(const std::string &srcFilename, const std::string &destFilename)
{
	INFO_LOG(COMMON, "Copy: %s --> %s", 
			srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
	if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE))
		return true;

	ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", 
			srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
	return false;
#else

	// buffer size
#define BSIZE 1024

	char buffer[BSIZE];

	// Open input file
	FILE *input = fopen(srcFilename.c_str(), "rb");
	if (!input)
	{
		ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", 
				srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
		return false;
	}

	// open output file
	FILE *output = fopen(destFilename.c_str(), "wb");
	if (!output)
	{
		fclose(input);
		ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", 
				srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
		return false;
	}

	// copy loop
	while (!feof(input))
	{
		// read input
		int rnum = fread(buffer, sizeof(char), BSIZE, input);
		if (rnum != BSIZE)
		{
			if (ferror(input) != 0)
			{
				ERROR_LOG(COMMON, 
						"Copy: failed reading from source, %s --> %s: %s", 
						srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
				goto bail;
			}
		}

		// write output
		int wnum = fwrite(buffer, sizeof(char), rnum, output);
		if (wnum != rnum)
		{
			ERROR_LOG(COMMON, 
					"Copy: failed writing to output, %s --> %s: %s", 
					srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
			goto bail;
		}
	}
	// close files
	fclose(input);
	fclose(output);
	return true;
bail:
	if (input)
		fclose(input);
	if (output)
		fclose(output);
	return false;
#endif
}
Пример #19
0
void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath)
{
	std::string GCMSearchPath;
	BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
#ifdef _WIN32
	WIN32_FIND_DATA findData;
	HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData);

	if (FindFirst != INVALID_HANDLE_VALUE)
	{
		bool bkeepLooping = true;

		while (bkeepLooping)
		{
			if (findData.cFileName[0] != '.')
			{
				std::string strFilename;
				BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName));
				m_FileNames.push_back(strFilename);
			}

			bkeepLooping = FindNextFile(FindFirst, &findData) ? true : false;
		}
	}
	FindClose(FindFirst);


#else
	// TODO: super lame/broken

	auto end_match(_searchString);

	// assuming we have a "*.blah"-like pattern
	if (!end_match.empty() && end_match[0] == '*')
		end_match.erase(0, 1);

	// ugly
	if (end_match == ".*")
		end_match.clear();

	DIR* dir = opendir(_strPath.c_str());

	if (!dir)
		return;

	while (auto const dp = readdir(dir))
	{
		std::string found(dp->d_name);

		if ((found != ".") && (found != "..") &&
		    (found.size() >= end_match.size()) &&
		    std::equal(end_match.rbegin(), end_match.rend(), found.rbegin()))
		{
			std::string full_name;
			if (_strPath.c_str()[_strPath.size() - 1] == DIR_SEP_CHR)
				full_name = _strPath + found;
			else
				full_name = _strPath + DIR_SEP + found;

			m_FileNames.push_back(full_name);
		}
	}

	closedir(dir);
#endif
}
Пример #20
0
// copies file srcFilename to destFilename, returns true on success
bool Copy(const std::string& srcFilename, const std::string& destFilename)
{
  INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
  if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE))
    return true;

  ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
            GetLastErrorMsg().c_str());
  return false;
#else

// buffer size
#define BSIZE 1024

  char buffer[BSIZE];

  // Open input file
  std::ifstream input;
  OpenFStream(input, srcFilename, std::ifstream::in | std::ifstream::binary);
  if (!input.is_open())
  {
    ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
              GetLastErrorMsg().c_str());
    return false;
  }

  // open output file
  File::IOFile output(destFilename, "wb");

  if (!output.IsOpen())
  {
    ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", srcFilename.c_str(),
              destFilename.c_str(), GetLastErrorMsg().c_str());
    return false;
  }

  // copy loop
  while (!input.eof())
  {
    // read input
    input.read(buffer, BSIZE);
    if (!input)
    {
      ERROR_LOG(COMMON, "Copy: failed reading from source, %s --> %s: %s", srcFilename.c_str(),
                destFilename.c_str(), GetLastErrorMsg().c_str());
      return false;
    }

    // write output
    if (!output.WriteBytes(buffer, BSIZE))
    {
      ERROR_LOG(COMMON, "Copy: failed writing to output, %s --> %s: %s", srcFilename.c_str(),
                destFilename.c_str(), GetLastErrorMsg().c_str());
      return false;
    }
  }

  return true;
#endif
}
Пример #21
0
// Recursive or non-recursive list of files and directories under directory.
FSTEntry ScanDirectoryTree(const std::string& directory, bool recursive)
{
  INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str());
  FSTEntry parent_entry;
  parent_entry.physicalName = directory;
  parent_entry.isDirectory = true;
  parent_entry.size = 0;
#ifdef _WIN32
  // Find the first file in the directory.
  WIN32_FIND_DATA ffd;

  HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd);
  if (hFind == INVALID_HANDLE_VALUE)
  {
    FindClose(hFind);
    return parent_entry;
  }
  // Windows loop
  do
  {
    const std::string virtual_name(TStrToUTF8(ffd.cFileName));
#else
  DIR* dirp = opendir(directory.c_str());
  if (!dirp)
    return parent_entry;

  // non Windows loop
  while (dirent* result = readdir(dirp))
  {
    const std::string virtual_name(result->d_name);
#endif
    if (virtual_name == "." || virtual_name == "..")
      continue;
    auto physical_name = directory + DIR_SEP + virtual_name;
    FSTEntry entry;
    const FileInfo file_info(physical_name);
    entry.isDirectory = file_info.IsDirectory();
    if (entry.isDirectory)
    {
      if (recursive)
        entry = ScanDirectoryTree(physical_name, true);
      else
        entry.size = 0;
      parent_entry.size += entry.size;
    }
    else
    {
      entry.size = file_info.GetSize();
    }
    entry.virtualName = virtual_name;
    entry.physicalName = physical_name;

    ++parent_entry.size;
    // Push into the tree
    parent_entry.children.push_back(entry);
#ifdef _WIN32
  } while (FindNextFile(hFind, &ffd) != 0);
  FindClose(hFind);
#else
  }
  closedir(dirp);
#endif

  return parent_entry;
}