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