chromium/net/third_party/quiche/src/quiche/common/platform/default/quiche_platform_impl/quiche_file_utils_impl.cc

// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "quiche_platform_impl/quiche_file_utils_impl.h"

#if defined(_WIN32)
#include <windows.h>
#else
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif  // defined(_WIN32)

#include <fstream>
#include <ios>
#include <iostream>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"

namespace quiche {

#if defined(_WIN32)
std::string JoinPathImpl(absl::string_view a, absl::string_view b) {
  if (a.empty()) {
    return std::string(b);
  }
  if (b.empty()) {
    return std::string(a);
  }
  // Win32 actually provides two different APIs for combining paths; one of them
  // has issues that could potentially lead to buffer overflow, and another is
  // not supported in Windows 7, which is why we're doing it manually.
  a = absl::StripSuffix(a, "/");
  a = absl::StripSuffix(a, "\\");
  return absl::StrCat(a, "\\", b);
}
#else
std::string JoinPathImpl(absl::string_view a, absl::string_view b) {}
#endif  // defined(_WIN32)

std::optional<std::string> ReadFileContentsImpl(absl::string_view file) {}

#if defined(_WIN32)

class ScopedDir {
 public:
  ScopedDir(HANDLE dir) : dir_(dir) {}
  ~ScopedDir() {
    if (dir_ != INVALID_HANDLE_VALUE) {
      // The API documentation explicitly says that CloseHandle() should not be
      // used on directory search handles.
      FindClose(dir_);
      dir_ = INVALID_HANDLE_VALUE;
    }
  }

  HANDLE get() { return dir_; }

 private:
  HANDLE dir_;
};

bool EnumerateDirectoryImpl(absl::string_view path,
                            std::vector<std::string>& directories,
                            std::vector<std::string>& files) {
  std::string path_owned(path);

  // Explicitly check that the directory we are trying to search is in fact a
  // directory.
  DWORD attributes = GetFileAttributesA(path_owned.c_str());
  if (attributes == INVALID_FILE_ATTRIBUTES) {
    return false;
  }
  if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
    return false;
  }

  std::string search_path = JoinPathImpl(path, "*");
  WIN32_FIND_DATAA file_data;
  ScopedDir dir(FindFirstFileA(search_path.c_str(), &file_data));
  if (dir.get() == INVALID_HANDLE_VALUE) {
    return GetLastError() == ERROR_FILE_NOT_FOUND;
  }
  do {
    std::string filename(file_data.cFileName);
    if (filename == "." || filename == "..") {
      continue;
    }
    if ((file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
      directories.push_back(std::move(filename));
    } else {
      files.push_back(std::move(filename));
    }
  } while (FindNextFileA(dir.get(), &file_data));
  return GetLastError() == ERROR_NO_MORE_FILES;
}

#else  // defined(_WIN32)

class ScopedDir {};

bool EnumerateDirectoryImpl(absl::string_view path,
                            std::vector<std::string>& directories,
                            std::vector<std::string>& files) {}

#endif  // defined(_WIN32)

}  // namespace quiche