- add sources.
[platform/framework/web/crosswalk.git] / src / base / file_util.cc
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 = file_util::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   file_util::CloseFile(file);
144
145   return true;
146 }
147
148 }  // namespace base
149
150 // -----------------------------------------------------------------------------
151
152 namespace file_util {
153
154 using base::FileEnumerator;
155 using base::FilePath;
156 using base::kMaxUniqueFiles;
157
158 bool IsDirectoryEmpty(const FilePath& dir_path) {
159   FileEnumerator files(dir_path, false,
160       FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
161   if (files.Next().empty())
162     return true;
163   return false;
164 }
165
166 FILE* CreateAndOpenTemporaryFile(FilePath* path) {
167   FilePath directory;
168   if (!GetTempDir(&directory))
169     return NULL;
170
171   return CreateAndOpenTemporaryFileInDir(directory, path);
172 }
173
174 bool CreateDirectory(const base::FilePath& full_path) {
175   return CreateDirectoryAndGetError(full_path, NULL);
176 }
177
178 bool GetFileSize(const FilePath& file_path, int64* file_size) {
179   base::PlatformFileInfo info;
180   if (!GetFileInfo(file_path, &info))
181     return false;
182   *file_size = info.size;
183   return true;
184 }
185
186 bool TouchFile(const FilePath& path,
187                const base::Time& last_accessed,
188                const base::Time& last_modified) {
189   int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE_ATTRIBUTES;
190
191 #if defined(OS_WIN)
192   // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
193   if (DirectoryExists(path))
194     flags |= base::PLATFORM_FILE_BACKUP_SEMANTICS;
195 #endif  // OS_WIN
196
197   const base::PlatformFile file =
198       base::CreatePlatformFile(path, flags, NULL, NULL);
199   if (file != base::kInvalidPlatformFileValue) {
200     bool result = base::TouchPlatformFile(file, last_accessed, last_modified);
201     base::ClosePlatformFile(file);
202     return result;
203   }
204
205   return false;
206 }
207
208 bool SetLastModifiedTime(const FilePath& path,
209                          const base::Time& last_modified) {
210   return TouchFile(path, last_modified, last_modified);
211 }
212
213 bool CloseFile(FILE* file) {
214   if (file == NULL)
215     return true;
216   return fclose(file) == 0;
217 }
218
219 bool TruncateFile(FILE* file) {
220   if (file == NULL)
221     return false;
222   long current_offset = ftell(file);
223   if (current_offset == -1)
224     return false;
225 #if defined(OS_WIN)
226   int fd = _fileno(file);
227   if (_chsize(fd, current_offset) != 0)
228     return false;
229 #else
230   int fd = fileno(file);
231   if (ftruncate(fd, current_offset) != 0)
232     return false;
233 #endif
234   return true;
235 }
236
237 int GetUniquePathNumber(
238     const FilePath& path,
239     const FilePath::StringType& suffix) {
240   bool have_suffix = !suffix.empty();
241   if (!PathExists(path) &&
242       (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
243     return 0;
244   }
245
246   FilePath new_path;
247   for (int count = 1; count <= kMaxUniqueFiles; ++count) {
248     new_path =
249         path.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", count));
250     if (!PathExists(new_path) &&
251         (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
252       return count;
253     }
254   }
255
256   return -1;
257 }
258
259 }  // namespace file_util