Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/file_util.h"
      6 
      7 #if defined(OS_WIN)
      8 #include <io.h>
      9 #endif
     10 #include <stdio.h>
     11 
     12 #include <fstream>
     13 
     14 #include "base/files/file_enumerator.h"
     15 #include "base/files/file_path.h"
     16 #include "base/logging.h"
     17 #include "base/strings/string_piece.h"
     18 #include "base/strings/string_util.h"
     19 #include "base/strings/stringprintf.h"
     20 #include "base/strings/utf_string_conversions.h"
     21 
     22 namespace base {
     23 
     24 namespace {
     25 
     26 const FilePath::CharType kExtensionSeparator = FILE_PATH_LITERAL('.');
     27 
     28 // The maximum number of 'uniquified' files we will try to create.
     29 // This is used when the filename we're trying to download is already in use,
     30 // so we create a new unique filename by appending " (nnn)" before the
     31 // extension, where 1 <= nnn <= kMaxUniqueFiles.
     32 // Also used by code that cleans up said files.
     33 static const int kMaxUniqueFiles = 100;
     34 
     35 }  // namespace
     36 
     37 bool g_bug108724_debug = false;
     38 
     39 int64 ComputeDirectorySize(const FilePath& root_path) {
     40   int64 running_size = 0;
     41   FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
     42   while (!file_iter.Next().empty())
     43     running_size += file_iter.GetInfo().GetSize();
     44   return running_size;
     45 }
     46 
     47 bool Move(const FilePath& from_path, const FilePath& to_path) {
     48   if (from_path.ReferencesParent() || to_path.ReferencesParent())
     49     return false;
     50   return internal::MoveUnsafe(from_path, to_path);
     51 }
     52 
     53 bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
     54   if (from_path.ReferencesParent() || to_path.ReferencesParent())
     55     return false;
     56   return internal::CopyFileUnsafe(from_path, to_path);
     57 }
     58 
     59 bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
     60   // We open the file in binary format even if they are text files because
     61   // we are just comparing that bytes are exactly same in both files and not
     62   // doing anything smart with text formatting.
     63   std::ifstream file1(filename1.value().c_str(),
     64                       std::ios::in | std::ios::binary);
     65   std::ifstream file2(filename2.value().c_str(),
     66                       std::ios::in | std::ios::binary);
     67 
     68   // Even if both files aren't openable (and thus, in some sense, "equal"),
     69   // any unusable file yields a result of "false".
     70   if (!file1.is_open() || !file2.is_open())
     71     return false;
     72 
     73   const int BUFFER_SIZE = 2056;
     74   char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
     75   do {
     76     file1.read(buffer1, BUFFER_SIZE);
     77     file2.read(buffer2, BUFFER_SIZE);
     78 
     79     if ((file1.eof() != file2.eof()) ||
     80         (file1.gcount() != file2.gcount()) ||
     81         (memcmp(buffer1, buffer2, file1.gcount()))) {
     82       file1.close();
     83       file2.close();
     84       return false;
     85     }
     86   } while (!file1.eof() || !file2.eof());
     87 
     88   file1.close();
     89   file2.close();
     90   return true;
     91 }
     92 
     93 bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
     94   std::ifstream file1(filename1.value().c_str(), std::ios::in);
     95   std::ifstream file2(filename2.value().c_str(), std::ios::in);
     96 
     97   // Even if both files aren't openable (and thus, in some sense, "equal"),
     98   // any unusable file yields a result of "false".
     99   if (!file1.is_open() || !file2.is_open())
    100     return false;
    101 
    102   do {
    103     std::string line1, line2;
    104     getline(file1, line1);
    105     getline(file2, line2);
    106 
    107     // Check for mismatched EOF states, or any error state.
    108     if ((file1.eof() != file2.eof()) ||
    109         file1.bad() || file2.bad()) {
    110       return false;
    111     }
    112 
    113     // Trim all '\r' and '\n' characters from the end of the line.
    114     std::string::size_type end1 = line1.find_last_not_of("\r\n");
    115     if (end1 == std::string::npos)
    116       line1.clear();
    117     else if (end1 + 1 < line1.length())
    118       line1.erase(end1 + 1);
    119 
    120     std::string::size_type end2 = line2.find_last_not_of("\r\n");
    121     if (end2 == std::string::npos)
    122       line2.clear();
    123     else if (end2 + 1 < line2.length())
    124       line2.erase(end2 + 1);
    125 
    126     if (line1 != line2)
    127       return false;
    128   } while (!file1.eof() || !file2.eof());
    129 
    130   return true;
    131 }
    132 
    133 }  // namespace base
    134 
    135 // -----------------------------------------------------------------------------
    136 
    137 namespace file_util {
    138 
    139 using base::FileEnumerator;
    140 using base::FilePath;
    141 using base::kExtensionSeparator;
    142 using base::kMaxUniqueFiles;
    143 
    144 bool ReadFileToString(const FilePath& path, std::string* contents) {
    145   if (path.ReferencesParent())
    146     return false;
    147   FILE* file = OpenFile(path, "rb");
    148   if (!file) {
    149     return false;
    150   }
    151 
    152   char buf[1 << 16];
    153   size_t len;
    154   while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
    155     if (contents)
    156       contents->append(buf, len);
    157   }
    158   CloseFile(file);
    159 
    160   return true;
    161 }
    162 
    163 bool IsDirectoryEmpty(const FilePath& dir_path) {
    164   FileEnumerator files(dir_path, false,
    165       FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
    166   if (files.Next().empty())
    167     return true;
    168   return false;
    169 }
    170 
    171 FILE* CreateAndOpenTemporaryFile(FilePath* path) {
    172   FilePath directory;
    173   if (!GetTempDir(&directory))
    174     return NULL;
    175 
    176   return CreateAndOpenTemporaryFileInDir(directory, path);
    177 }
    178 
    179 bool CreateDirectory(const base::FilePath& full_path) {
    180   return CreateDirectoryAndGetError(full_path, NULL);
    181 }
    182 
    183 bool GetFileSize(const FilePath& file_path, int64* file_size) {
    184   base::PlatformFileInfo info;
    185   if (!GetFileInfo(file_path, &info))
    186     return false;
    187   *file_size = info.size;
    188   return true;
    189 }
    190 
    191 bool TouchFile(const FilePath& path,
    192                const base::Time& last_accessed,
    193                const base::Time& last_modified) {
    194   int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
    195 
    196 #if defined(OS_WIN)
    197   // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
    198   if (DirectoryExists(path))
    199     flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
    200 #endif  // OS_WIN
    201 
    202   const base::PlatformFile file =
    203       base::CreatePlatformFile(path, flags, NULL, NULL);
    204   if (file != base::kInvalidPlatformFileValue) {
    205     bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
    206     base::ClosePlatformFile(file);
    207     return result;
    208   }
    209 
    210   return false;
    211 }
    212 
    213 bool SetLastModifiedTime(const FilePath& path,
    214                          const base::Time& last_modified) {
    215   return TouchFile(path, last_modified, last_modified);
    216 }
    217 
    218 bool CloseFile(FILE* file) {
    219   if (file == NULL)
    220     return true;
    221   return fclose(file) == 0;
    222 }
    223 
    224 bool TruncateFile(FILE* file) {
    225   if (file == NULL)
    226     return false;
    227   long current_offset = ftell(file);
    228   if (current_offset == -1)
    229     return false;
    230 #if defined(OS_WIN)
    231   int fd = _fileno(file);
    232   if (_chsize(fd, current_offset) != 0)
    233     return false;
    234 #else
    235   int fd = fileno(file);
    236   if (ftruncate(fd, current_offset) != 0)
    237     return false;
    238 #endif
    239   return true;
    240 }
    241 
    242 int GetUniquePathNumber(
    243     const FilePath& path,
    244     const FilePath::StringType& suffix) {
    245   bool have_suffix = !suffix.empty();
    246   if (!PathExists(path) &&
    247       (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
    248     return 0;
    249   }
    250 
    251   FilePath new_path;
    252   for (int count = 1; count <= kMaxUniqueFiles; ++count) {
    253     new_path =
    254         path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
    255     if (!PathExists(new_path) &&
    256         (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
    257       return count;
    258     }
    259   }
    260 
    261   return -1;
    262 }
    263 
    264 }  // namespace file_util
    265