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