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