16d528ed9Sopenharmony_ci// Copyright (c) 2012 The Chromium Authors. All rights reserved.
26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
36d528ed9Sopenharmony_ci// found in the LICENSE file.
46d528ed9Sopenharmony_ci
56d528ed9Sopenharmony_ci#include "base/files/file_util.h"
66d528ed9Sopenharmony_ci
76d528ed9Sopenharmony_ci#if defined(OS_WIN)
86d528ed9Sopenharmony_ci#include <io.h>
96d528ed9Sopenharmony_ci#endif
106d528ed9Sopenharmony_ci#include <stdio.h>
116d528ed9Sopenharmony_ci
126d528ed9Sopenharmony_ci#include <fstream>
136d528ed9Sopenharmony_ci#include <limits>
146d528ed9Sopenharmony_ci#include <string_view>
156d528ed9Sopenharmony_ci
166d528ed9Sopenharmony_ci#include "base/files/file_enumerator.h"
176d528ed9Sopenharmony_ci#include "base/files/file_path.h"
186d528ed9Sopenharmony_ci#include "base/logging.h"
196d528ed9Sopenharmony_ci#include "base/strings/string_util.h"
206d528ed9Sopenharmony_ci#include "base/strings/stringprintf.h"
216d528ed9Sopenharmony_ci#include "base/strings/utf_string_conversions.h"
226d528ed9Sopenharmony_ci#include "util/build_config.h"
236d528ed9Sopenharmony_ci
246d528ed9Sopenharmony_cinamespace base {
256d528ed9Sopenharmony_ci
266d528ed9Sopenharmony_cinamespace {
276d528ed9Sopenharmony_ci
286d528ed9Sopenharmony_ci// The maximum number of 'uniquified' files we will try to create.
296d528ed9Sopenharmony_ci// This is used when the filename we're trying to download is already in use,
306d528ed9Sopenharmony_ci// so we create a new unique filename by appending " (nnn)" before the
316d528ed9Sopenharmony_ci// extension, where 1 <= nnn <= kMaxUniqueFiles.
326d528ed9Sopenharmony_ci// Also used by code that cleans up said files.
336d528ed9Sopenharmony_cistatic const int kMaxUniqueFiles = 100;
346d528ed9Sopenharmony_ci
356d528ed9Sopenharmony_ci}  // namespace
366d528ed9Sopenharmony_ci
376d528ed9Sopenharmony_ciint64_t ComputeDirectorySize(const FilePath& root_path) {
386d528ed9Sopenharmony_ci  int64_t running_size = 0;
396d528ed9Sopenharmony_ci  FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
406d528ed9Sopenharmony_ci  while (!file_iter.Next().empty())
416d528ed9Sopenharmony_ci    running_size += file_iter.GetInfo().GetSize();
426d528ed9Sopenharmony_ci  return running_size;
436d528ed9Sopenharmony_ci}
446d528ed9Sopenharmony_ci
456d528ed9Sopenharmony_cibool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
466d528ed9Sopenharmony_ci  // We open the file in binary format even if they are text files because
476d528ed9Sopenharmony_ci  // we are just comparing that bytes are exactly same in both files and not
486d528ed9Sopenharmony_ci  // doing anything smart with text formatting.
496d528ed9Sopenharmony_ci  std::ifstream file1(filename1.As8Bit().c_str(),
506d528ed9Sopenharmony_ci                      std::ios::in | std::ios::binary);
516d528ed9Sopenharmony_ci  std::ifstream file2(filename2.As8Bit().c_str(),
526d528ed9Sopenharmony_ci                      std::ios::in | std::ios::binary);
536d528ed9Sopenharmony_ci
546d528ed9Sopenharmony_ci  // Even if both files aren't openable (and thus, in some sense, "equal"),
556d528ed9Sopenharmony_ci  // any unusable file yields a result of "false".
566d528ed9Sopenharmony_ci  if (!file1.is_open() || !file2.is_open())
576d528ed9Sopenharmony_ci    return false;
586d528ed9Sopenharmony_ci
596d528ed9Sopenharmony_ci  const int BUFFER_SIZE = 2056;
606d528ed9Sopenharmony_ci  char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
616d528ed9Sopenharmony_ci  do {
626d528ed9Sopenharmony_ci    file1.read(buffer1, BUFFER_SIZE);
636d528ed9Sopenharmony_ci    file2.read(buffer2, BUFFER_SIZE);
646d528ed9Sopenharmony_ci
656d528ed9Sopenharmony_ci    if ((file1.eof() != file2.eof()) || (file1.gcount() != file2.gcount()) ||
666d528ed9Sopenharmony_ci        (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
676d528ed9Sopenharmony_ci      file1.close();
686d528ed9Sopenharmony_ci      file2.close();
696d528ed9Sopenharmony_ci      return false;
706d528ed9Sopenharmony_ci    }
716d528ed9Sopenharmony_ci  } while (!file1.eof() || !file2.eof());
726d528ed9Sopenharmony_ci
736d528ed9Sopenharmony_ci  file1.close();
746d528ed9Sopenharmony_ci  file2.close();
756d528ed9Sopenharmony_ci  return true;
766d528ed9Sopenharmony_ci}
776d528ed9Sopenharmony_ci
786d528ed9Sopenharmony_cibool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
796d528ed9Sopenharmony_ci  std::ifstream file1(filename1.As8Bit().c_str(), std::ios::in);
806d528ed9Sopenharmony_ci  std::ifstream file2(filename2.As8Bit().c_str(), std::ios::in);
816d528ed9Sopenharmony_ci
826d528ed9Sopenharmony_ci  // Even if both files aren't openable (and thus, in some sense, "equal"),
836d528ed9Sopenharmony_ci  // any unusable file yields a result of "false".
846d528ed9Sopenharmony_ci  if (!file1.is_open() || !file2.is_open())
856d528ed9Sopenharmony_ci    return false;
866d528ed9Sopenharmony_ci
876d528ed9Sopenharmony_ci  do {
886d528ed9Sopenharmony_ci    std::string line1, line2;
896d528ed9Sopenharmony_ci    getline(file1, line1);
906d528ed9Sopenharmony_ci    getline(file2, line2);
916d528ed9Sopenharmony_ci
926d528ed9Sopenharmony_ci    // Check for mismatched EOF states, or any error state.
936d528ed9Sopenharmony_ci    if ((file1.eof() != file2.eof()) || file1.bad() || file2.bad()) {
946d528ed9Sopenharmony_ci      return false;
956d528ed9Sopenharmony_ci    }
966d528ed9Sopenharmony_ci
976d528ed9Sopenharmony_ci    // Trim all '\r' and '\n' characters from the end of the line.
986d528ed9Sopenharmony_ci    std::string::size_type end1 = line1.find_last_not_of("\r\n");
996d528ed9Sopenharmony_ci    if (end1 == std::string::npos)
1006d528ed9Sopenharmony_ci      line1.clear();
1016d528ed9Sopenharmony_ci    else if (end1 + 1 < line1.length())
1026d528ed9Sopenharmony_ci      line1.erase(end1 + 1);
1036d528ed9Sopenharmony_ci
1046d528ed9Sopenharmony_ci    std::string::size_type end2 = line2.find_last_not_of("\r\n");
1056d528ed9Sopenharmony_ci    if (end2 == std::string::npos)
1066d528ed9Sopenharmony_ci      line2.clear();
1076d528ed9Sopenharmony_ci    else if (end2 + 1 < line2.length())
1086d528ed9Sopenharmony_ci      line2.erase(end2 + 1);
1096d528ed9Sopenharmony_ci
1106d528ed9Sopenharmony_ci    if (line1 != line2)
1116d528ed9Sopenharmony_ci      return false;
1126d528ed9Sopenharmony_ci  } while (!file1.eof() || !file2.eof());
1136d528ed9Sopenharmony_ci
1146d528ed9Sopenharmony_ci  return true;
1156d528ed9Sopenharmony_ci}
1166d528ed9Sopenharmony_ci
1176d528ed9Sopenharmony_cibool ReadFileToStringWithMaxSize(const FilePath& path,
1186d528ed9Sopenharmony_ci                                 std::string* contents,
1196d528ed9Sopenharmony_ci                                 size_t max_size) {
1206d528ed9Sopenharmony_ci  if (contents)
1216d528ed9Sopenharmony_ci    contents->clear();
1226d528ed9Sopenharmony_ci  if (path.ReferencesParent())
1236d528ed9Sopenharmony_ci    return false;
1246d528ed9Sopenharmony_ci  FILE* file = OpenFile(path, "rb");
1256d528ed9Sopenharmony_ci  if (!file) {
1266d528ed9Sopenharmony_ci    return false;
1276d528ed9Sopenharmony_ci  }
1286d528ed9Sopenharmony_ci
1296d528ed9Sopenharmony_ci  // Many files supplied in |path| have incorrect size (proc files etc).
1306d528ed9Sopenharmony_ci  // Hence, the file is read sequentially as opposed to a one-shot read, using
1316d528ed9Sopenharmony_ci  // file size as a hint for chunk size if available.
1326d528ed9Sopenharmony_ci  constexpr int64_t kDefaultChunkSize = 1 << 16;
1336d528ed9Sopenharmony_ci  int64_t chunk_size;
1346d528ed9Sopenharmony_ci  if (!GetFileSize(path, &chunk_size) || chunk_size <= 0)
1356d528ed9Sopenharmony_ci    chunk_size = kDefaultChunkSize - 1;
1366d528ed9Sopenharmony_ci  // We need to attempt to read at EOF for feof flag to be set so here we
1376d528ed9Sopenharmony_ci  // use |chunk_size| + 1.
1386d528ed9Sopenharmony_ci  chunk_size = std::min<uint64_t>(chunk_size, max_size) + 1;
1396d528ed9Sopenharmony_ci  size_t bytes_read_this_pass;
1406d528ed9Sopenharmony_ci  size_t bytes_read_so_far = 0;
1416d528ed9Sopenharmony_ci  bool read_status = true;
1426d528ed9Sopenharmony_ci  std::string local_contents;
1436d528ed9Sopenharmony_ci  local_contents.resize(chunk_size);
1446d528ed9Sopenharmony_ci
1456d528ed9Sopenharmony_ci  while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1,
1466d528ed9Sopenharmony_ci                                       chunk_size, file)) > 0) {
1476d528ed9Sopenharmony_ci    if ((max_size - bytes_read_so_far) < bytes_read_this_pass) {
1486d528ed9Sopenharmony_ci      // Read more than max_size bytes, bail out.
1496d528ed9Sopenharmony_ci      bytes_read_so_far = max_size;
1506d528ed9Sopenharmony_ci      read_status = false;
1516d528ed9Sopenharmony_ci      break;
1526d528ed9Sopenharmony_ci    }
1536d528ed9Sopenharmony_ci    // In case EOF was not reached, iterate again but revert to the default
1546d528ed9Sopenharmony_ci    // chunk size.
1556d528ed9Sopenharmony_ci    if (bytes_read_so_far == 0)
1566d528ed9Sopenharmony_ci      chunk_size = kDefaultChunkSize;
1576d528ed9Sopenharmony_ci
1586d528ed9Sopenharmony_ci    bytes_read_so_far += bytes_read_this_pass;
1596d528ed9Sopenharmony_ci    // Last fread syscall (after EOF) can be avoided via feof, which is just a
1606d528ed9Sopenharmony_ci    // flag check.
1616d528ed9Sopenharmony_ci    if (feof(file))
1626d528ed9Sopenharmony_ci      break;
1636d528ed9Sopenharmony_ci    local_contents.resize(bytes_read_so_far + chunk_size);
1646d528ed9Sopenharmony_ci  }
1656d528ed9Sopenharmony_ci  read_status = read_status && !ferror(file);
1666d528ed9Sopenharmony_ci  CloseFile(file);
1676d528ed9Sopenharmony_ci  if (contents) {
1686d528ed9Sopenharmony_ci    contents->swap(local_contents);
1696d528ed9Sopenharmony_ci    contents->resize(bytes_read_so_far);
1706d528ed9Sopenharmony_ci  }
1716d528ed9Sopenharmony_ci
1726d528ed9Sopenharmony_ci  return read_status;
1736d528ed9Sopenharmony_ci}
1746d528ed9Sopenharmony_ci
1756d528ed9Sopenharmony_cibool ReadFileToString(const FilePath& path, std::string* contents) {
1766d528ed9Sopenharmony_ci  return ReadFileToStringWithMaxSize(path, contents,
1776d528ed9Sopenharmony_ci                                     std::numeric_limits<size_t>::max());
1786d528ed9Sopenharmony_ci}
1796d528ed9Sopenharmony_ci
1806d528ed9Sopenharmony_cibool IsDirectoryEmpty(const FilePath& dir_path) {
1816d528ed9Sopenharmony_ci  FileEnumerator files(dir_path, false,
1826d528ed9Sopenharmony_ci                       FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
1836d528ed9Sopenharmony_ci  if (files.Next().empty())
1846d528ed9Sopenharmony_ci    return true;
1856d528ed9Sopenharmony_ci  return false;
1866d528ed9Sopenharmony_ci}
1876d528ed9Sopenharmony_ci
1886d528ed9Sopenharmony_cibool CreateDirectory(const FilePath& full_path) {
1896d528ed9Sopenharmony_ci  return CreateDirectoryAndGetError(full_path, nullptr);
1906d528ed9Sopenharmony_ci}
1916d528ed9Sopenharmony_ci
1926d528ed9Sopenharmony_cibool GetFileSize(const FilePath& file_path, int64_t* file_size) {
1936d528ed9Sopenharmony_ci  File::Info info;
1946d528ed9Sopenharmony_ci  if (!GetFileInfo(file_path, &info))
1956d528ed9Sopenharmony_ci    return false;
1966d528ed9Sopenharmony_ci  *file_size = info.size;
1976d528ed9Sopenharmony_ci  return true;
1986d528ed9Sopenharmony_ci}
1996d528ed9Sopenharmony_ci
2006d528ed9Sopenharmony_cibool CloseFile(FILE* file) {
2016d528ed9Sopenharmony_ci  if (file == nullptr)
2026d528ed9Sopenharmony_ci    return true;
2036d528ed9Sopenharmony_ci  return fclose(file) == 0;
2046d528ed9Sopenharmony_ci}
2056d528ed9Sopenharmony_ci
2066d528ed9Sopenharmony_cibool TruncateFile(FILE* file) {
2076d528ed9Sopenharmony_ci  if (file == nullptr)
2086d528ed9Sopenharmony_ci    return false;
2096d528ed9Sopenharmony_ci  long current_offset = ftell(file);
2106d528ed9Sopenharmony_ci  if (current_offset == -1)
2116d528ed9Sopenharmony_ci    return false;
2126d528ed9Sopenharmony_ci#if defined(OS_WIN)
2136d528ed9Sopenharmony_ci  int fd = _fileno(file);
2146d528ed9Sopenharmony_ci  if (_chsize(fd, current_offset) != 0)
2156d528ed9Sopenharmony_ci    return false;
2166d528ed9Sopenharmony_ci#else
2176d528ed9Sopenharmony_ci  int fd = fileno(file);
2186d528ed9Sopenharmony_ci  if (ftruncate(fd, current_offset) != 0)
2196d528ed9Sopenharmony_ci    return false;
2206d528ed9Sopenharmony_ci#endif
2216d528ed9Sopenharmony_ci  return true;
2226d528ed9Sopenharmony_ci}
2236d528ed9Sopenharmony_ci
2246d528ed9Sopenharmony_ciint GetUniquePathNumber(const FilePath& path,
2256d528ed9Sopenharmony_ci                        const FilePath::StringType& suffix) {
2266d528ed9Sopenharmony_ci  bool have_suffix = !suffix.empty();
2276d528ed9Sopenharmony_ci  if (!PathExists(path) &&
2286d528ed9Sopenharmony_ci      (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
2296d528ed9Sopenharmony_ci    return 0;
2306d528ed9Sopenharmony_ci  }
2316d528ed9Sopenharmony_ci
2326d528ed9Sopenharmony_ci  FilePath new_path;
2336d528ed9Sopenharmony_ci  for (int count = 1; count <= kMaxUniqueFiles; ++count) {
2346d528ed9Sopenharmony_ci    new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
2356d528ed9Sopenharmony_ci    if (!PathExists(new_path) &&
2366d528ed9Sopenharmony_ci        (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
2376d528ed9Sopenharmony_ci      return count;
2386d528ed9Sopenharmony_ci    }
2396d528ed9Sopenharmony_ci  }
2406d528ed9Sopenharmony_ci
2416d528ed9Sopenharmony_ci  return -1;
2426d528ed9Sopenharmony_ci}
2436d528ed9Sopenharmony_ci
2446d528ed9Sopenharmony_ci}  // namespace base
245