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