blob: d44b7431e2d98a8b79dbe1863bfcf202f0682729 [file] [log] [blame]
[email protected]b2e97292008-09-02 18:20:341// Copyright (c) 2006-2008 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
[email protected]21dec3872008-09-18 19:15:547#include <errno.h>
[email protected]b2e97292008-09-02 18:20:348#include <fcntl.h>
9#include <fnmatch.h>
10#include <fts.h>
11#include <libgen.h>
[email protected]836f1342008-10-01 17:40:1312#include <stdio.h>
[email protected]21dec3872008-09-18 19:15:5413#include <string.h>
[email protected]b2e97292008-09-02 18:20:3414#include <sys/errno.h>
[email protected]7856bb82008-12-12 23:43:0315#include <sys/mman.h>
[email protected]b2e97292008-09-02 18:20:3416#include <sys/stat.h>
17#include <time.h>
18
19#include <fstream>
20
21#include "base/basictypes.h"
[email protected]640517f2008-10-30 23:54:0422#include "base/file_path.h"
[email protected]b2e97292008-09-02 18:20:3423#include "base/logging.h"
24#include "base/string_util.h"
25
26namespace file_util {
27
[email protected]392264c2008-11-11 00:01:3828static const char* kTempFileName = "com.google.chrome.XXXXXX";
[email protected]778e8c52008-09-11 17:36:2329
[email protected]b2e97292008-09-02 18:20:3430std::wstring GetDirectoryFromPath(const std::wstring& path) {
31 if (EndsWithSeparator(path)) {
32 std::wstring dir = path;
33 TrimTrailingSeparator(&dir);
34 return dir;
35 } else {
36 char full_path[PATH_MAX];
37 base::strlcpy(full_path, WideToUTF8(path).c_str(), arraysize(full_path));
38 return UTF8ToWide(dirname(full_path));
39 }
40}
41
[email protected]640517f2008-10-30 23:54:0442bool AbsolutePath(FilePath* path) {
[email protected]b2e97292008-09-02 18:20:3443 char full_path[PATH_MAX];
[email protected]640517f2008-10-30 23:54:0444 if (realpath(path->value().c_str(), full_path) == NULL)
[email protected]b2e97292008-09-02 18:20:3445 return false;
[email protected]640517f2008-10-30 23:54:0446 *path = FilePath(full_path);
[email protected]b2e97292008-09-02 18:20:3447 return true;
48}
49
50// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
51// which works both with and without the recursive flag. I'm not sure we need
52// that functionality. If not, remove from file_util_win.cc, otherwise add it
53// here.
[email protected]640517f2008-10-30 23:54:0454bool Delete(const FilePath& path, bool recursive) {
55 const char* path_str = path.value().c_str();
[email protected]b2e97292008-09-02 18:20:3456 struct stat64 file_info;
[email protected]640517f2008-10-30 23:54:0457 int test = stat64(path_str, &file_info);
[email protected]b2e97292008-09-02 18:20:3458 if (test != 0) {
59 // The Windows version defines this condition as success.
60 bool ret = (errno == ENOENT || errno == ENOTDIR);
61 return ret;
62 }
63 if (!S_ISDIR(file_info.st_mode))
[email protected]640517f2008-10-30 23:54:0464 return (unlink(path_str) == 0);
[email protected]b2e97292008-09-02 18:20:3465 if (!recursive)
[email protected]640517f2008-10-30 23:54:0466 return (rmdir(path_str) == 0);
[email protected]b2e97292008-09-02 18:20:3467
68 bool success = true;
69 int ftsflags = FTS_PHYSICAL | FTS_NOSTAT;
70 char top_dir[PATH_MAX];
[email protected]640517f2008-10-30 23:54:0471 if (base::strlcpy(top_dir, path_str,
[email protected]21dec3872008-09-18 19:15:5472 arraysize(top_dir)) >= arraysize(top_dir)) {
73 return false;
74 }
[email protected]b2e97292008-09-02 18:20:3475 char* dir_list[2] = { top_dir, NULL };
76 FTS* fts = fts_open(dir_list, ftsflags, NULL);
77 if (fts) {
78 FTSENT* fts_ent = fts_read(fts);
79 while (success && fts_ent != NULL) {
80 switch (fts_ent->fts_info) {
81 case FTS_DNR:
82 case FTS_ERR:
83 // log error
84 success = false;
85 continue;
86 break;
87 case FTS_DP:
[email protected]7e1fde6a2008-12-23 20:20:1088 success = (rmdir(fts_ent->fts_accpath) == 0);
[email protected]b2e97292008-09-02 18:20:3489 break;
90 case FTS_D:
91 break;
92 case FTS_NSOK:
93 case FTS_F:
94 case FTS_SL:
95 case FTS_SLNONE:
[email protected]7e1fde6a2008-12-23 20:20:1096 success = (unlink(fts_ent->fts_accpath) == 0);
[email protected]b2e97292008-09-02 18:20:3497 break;
98 default:
99 DCHECK(false);
100 break;
101 }
102 fts_ent = fts_read(fts);
103 }
104 fts_close(fts);
105 }
106 return success;
107}
108
[email protected]640517f2008-10-30 23:54:04109bool Move(const FilePath& from_path, const FilePath& to_path) {
110 return (rename(from_path.value().c_str(),
111 to_path.value().c_str()) == 0);
[email protected]b2e97292008-09-02 18:20:34112}
113
[email protected]640517f2008-10-30 23:54:04114bool CopyDirectory(const FilePath& from_path,
115 const FilePath& to_path,
[email protected]21dec3872008-09-18 19:15:54116 bool recursive) {
[email protected]21dec3872008-09-18 19:15:54117 // Some old callers of CopyDirectory want it to support wildcards.
118 // After some discussion, we decided to fix those callers.
119 // Break loudly here if anyone tries to do this.
120 // TODO(evanm): remove this once we're sure it's ok.
[email protected]640517f2008-10-30 23:54:04121 DCHECK(to_path.value().find('*') == std::string::npos);
122 DCHECK(from_path.value().find('*') == std::string::npos);
[email protected]21dec3872008-09-18 19:15:54123
124 char top_dir[PATH_MAX];
[email protected]640517f2008-10-30 23:54:04125 if (base::strlcpy(top_dir, from_path.value().c_str(),
[email protected]21dec3872008-09-18 19:15:54126 arraysize(top_dir)) >= arraysize(top_dir)) {
127 return false;
128 }
129
130 char* dir_list[] = { top_dir, NULL };
131 FTS* fts = fts_open(dir_list, FTS_PHYSICAL | FTS_NOSTAT, NULL);
132 if (!fts) {
133 LOG(ERROR) << "fts_open failed: " << strerror(errno);
134 return false;
135 }
136
137 int error = 0;
138 FTSENT* ent;
139 while (!error && (ent = fts_read(fts)) != NULL) {
140 // ent->fts_path is the source path, including from_path, so paste
141 // the suffix after from_path onto to_path to create the target_path.
[email protected]ca0209612009-01-13 18:57:46142 std::string suffix(&ent->fts_path[from_path.value().size()]);
143 // Strip the leading '/' (if any).
144 if (!suffix.empty()) {
145 DCHECK(suffix[0] == '/');
146 suffix.erase(0, 1);
147 }
148 const FilePath target_path = to_path.Append(suffix);
[email protected]21dec3872008-09-18 19:15:54149 switch (ent->fts_info) {
150 case FTS_D: // Preorder directory.
151 // If we encounter a subdirectory in a non-recursive copy, prune it
152 // from the traversal.
153 if (!recursive && ent->fts_level > 0) {
154 if (fts_set(fts, ent, FTS_SKIP) != 0)
155 error = errno;
156 continue;
157 }
158
159 // Try creating the target dir, continuing on it if it exists already.
[email protected]ca0209612009-01-13 18:57:46160 if (mkdir(target_path.value().c_str(), 0777) != 0) {
[email protected]21dec3872008-09-18 19:15:54161 if (errno != EEXIST)
162 error = errno;
163 }
164 break;
165 case FTS_F: // Regular file.
166 case FTS_NSOK: // File, no stat info requested.
[email protected]21dec3872008-09-18 19:15:54167 errno = 0;
[email protected]ca0209612009-01-13 18:57:46168 if (!CopyFile(FilePath(ent->fts_path), target_path))
[email protected]21dec3872008-09-18 19:15:54169 error = errno ? errno : EINVAL;
170 break;
171 case FTS_DP: // Postorder directory.
172 case FTS_DOT: // "." or ".."
173 // Skip it.
174 continue;
175 case FTS_DC: // Directory causing a cycle.
176 // Skip this branch.
177 if (fts_set(fts, ent, FTS_SKIP) != 0)
178 error = errno;
179 break;
180 case FTS_DNR: // Directory cannot be read.
181 case FTS_ERR: // Error.
182 case FTS_NS: // Stat failed.
183 // Abort with the error.
184 error = ent->fts_errno;
185 break;
186 case FTS_SL: // Symlink.
187 case FTS_SLNONE: // Symlink with broken target.
188 LOG(WARNING) << "CopyDirectory() skipping symbolic link.";
189 continue;
190 case FTS_DEFAULT: // Some other sort of file.
191 LOG(WARNING) << "CopyDirectory() skipping weird file.";
192 continue;
193 default:
194 NOTREACHED();
195 continue; // Hope for the best!
196 }
197 }
198 // fts_read may have returned NULL and set errno to indicate an error.
199 if (!error && errno != 0)
200 error = errno;
201
202 if (!fts_close(fts)) {
203 // If we already have an error, let's use that error instead of the error
204 // fts_close set.
205 if (!error)
206 error = errno;
207 }
208
209 if (error) {
210 LOG(ERROR) << "CopyDirectory(): " << strerror(error);
211 return false;
212 }
213 return true;
[email protected]b2e97292008-09-02 18:20:34214}
215
[email protected]640517f2008-10-30 23:54:04216bool PathExists(const FilePath& path) {
[email protected]b2e97292008-09-02 18:20:34217 struct stat64 file_info;
[email protected]640517f2008-10-30 23:54:04218 return (stat64(path.value().c_str(), &file_info) == 0);
[email protected]b2e97292008-09-02 18:20:34219}
220
[email protected]7e1fde6a2008-12-23 20:20:10221bool PathIsWritable(const FilePath& path) {
222 FilePath test_path(path);
223 struct stat64 file_info;
224 if (stat64(test_path.value().c_str(), &file_info) != 0) {
225 // If the path doesn't exist, test the parent dir.
226 test_path = test_path.DirName();
227 // If the parent dir doesn't exist, then return false (the path is not
228 // directly writable).
229 if (stat64(test_path.value().c_str(), &file_info) != 0)
230 return false;
231 }
232 if (S_IWOTH & file_info.st_mode)
233 return true;
234 if (getegid() == file_info.st_gid && (S_IWGRP & file_info.st_mode))
235 return true;
236 if (geteuid() == file_info.st_uid && (S_IWUSR & file_info.st_mode))
237 return true;
238 return false;
239}
240
[email protected]640517f2008-10-30 23:54:04241bool DirectoryExists(const FilePath& path) {
[email protected]806b9c62008-09-11 16:09:11242 struct stat64 file_info;
[email protected]640517f2008-10-30 23:54:04243 if (stat64(path.value().c_str(), &file_info) == 0)
[email protected]806b9c62008-09-11 16:09:11244 return S_ISDIR(file_info.st_mode);
245 return false;
246}
247
[email protected]b2e97292008-09-02 18:20:34248// TODO(erikkay): implement
249#if 0
250bool GetFileCreationLocalTimeFromHandle(int fd,
251 LPSYSTEMTIME creation_time) {
252 if (!file_handle)
253 return false;
254
255 FILETIME utc_filetime;
256 if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
257 return false;
258
259 FILETIME local_filetime;
260 if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
261 return false;
262
263 return !!FileTimeToSystemTime(&local_filetime, creation_time);
264}
265
266bool GetFileCreationLocalTime(const std::string& filename,
267 LPSYSTEMTIME creation_time) {
268 ScopedHandle file_handle(
269 CreateFile(filename.c_str(), GENERIC_READ,
270 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
271 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
272 return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
273}
274#endif
275
[email protected]392264c2008-11-11 00:01:38276bool CreateTemporaryFileName(FilePath* path) {
277 if (!GetTempDir(path))
[email protected]b2e97292008-09-02 18:20:34278 return false;
[email protected]392264c2008-11-11 00:01:38279
280 *path = path->Append(kTempFileName);
281 std::string tmpdir_string = path->value();
[email protected]778e8c52008-09-11 17:36:23282 // this should be OK since mkstemp just replaces characters in place
283 char* buffer = const_cast<char*>(tmpdir_string.c_str());
[email protected]392264c2008-11-11 00:01:38284
[email protected]778e8c52008-09-11 17:36:23285 int fd = mkstemp(buffer);
[email protected]b2e97292008-09-02 18:20:34286 if (fd < 0)
287 return false;
[email protected]392264c2008-11-11 00:01:38288
289 close(fd);
[email protected]b2e97292008-09-02 18:20:34290 return true;
291}
292
[email protected]9ccbb372008-10-10 18:50:32293bool CreateTemporaryFileNameInDir(const std::wstring& dir,
294 std::wstring* temp_file) {
295 // Not implemented yet.
296 NOTREACHED();
297 return false;
298}
299
[email protected]7e1fde6a2008-12-23 20:20:10300bool CreateNewTempDirectory(const FilePath::StringType& prefix,
301 FilePath* new_temp_path) {
[email protected]392264c2008-11-11 00:01:38302 FilePath tmpdir;
[email protected]b2e97292008-09-02 18:20:34303 if (!GetTempDir(&tmpdir))
304 return false;
[email protected]392264c2008-11-11 00:01:38305 tmpdir = tmpdir.Append(kTempFileName);
306 std::string tmpdir_string = tmpdir.value();
[email protected]b2e97292008-09-02 18:20:34307 // this should be OK since mkdtemp just replaces characters in place
[email protected]778e8c52008-09-11 17:36:23308 char* buffer = const_cast<char*>(tmpdir_string.c_str());
[email protected]b2e97292008-09-02 18:20:34309 char* dtemp = mkdtemp(buffer);
310 if (!dtemp)
311 return false;
[email protected]7e1fde6a2008-12-23 20:20:10312 *new_temp_path = FilePath(dtemp);
[email protected]b2e97292008-09-02 18:20:34313 return true;
314}
315
[email protected]640517f2008-10-30 23:54:04316bool CreateDirectory(const FilePath& full_path) {
317 std::vector<FilePath> subpaths;
318
319 // Collect a list of all parent directories.
320 FilePath last_path = full_path;
321 subpaths.push_back(full_path);
322 for (FilePath path = full_path.DirName();
323 path.value() != last_path.value(); path = path.DirName()) {
324 subpaths.push_back(path);
325 last_path = path;
326 }
327
328 // Iterate through the parents and create the missing ones.
329 for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
330 i != subpaths.rend(); ++i) {
331 if (!DirectoryExists(*i)) {
332 if (mkdir(i->value().c_str(), 0777) != 0)
[email protected]b2e97292008-09-02 18:20:34333 return false;
334 }
335 }
336 return true;
337}
338
[email protected]eac0709a2008-11-04 21:00:46339bool GetFileInfo(const FilePath& file_path, FileInfo* results) {
[email protected]b2e97292008-09-02 18:20:34340 struct stat64 file_info;
[email protected]eac0709a2008-11-04 21:00:46341 if (stat64(file_path.value().c_str(), &file_info) != 0)
[email protected]b2e97292008-09-02 18:20:34342 return false;
[email protected]f5e3da4d2008-09-26 01:04:08343 results->is_directory = S_ISDIR(file_info.st_mode);
344 results->size = file_info.st_size;
[email protected]b2e97292008-09-02 18:20:34345 return true;
346}
347
[email protected]836f1342008-10-01 17:40:13348FILE* OpenFile(const std::string& filename, const char* mode) {
[email protected]a9cd2a652008-11-17 21:01:19349 return OpenFile(FilePath(filename), mode);
[email protected]836f1342008-10-01 17:40:13350}
351
[email protected]a9cd2a652008-11-17 21:01:19352FILE* OpenFile(const FilePath& filename, const char* mode) {
353 return fopen(filename.value().c_str(), mode);
[email protected]836f1342008-10-01 17:40:13354}
355
[email protected]c870c762009-01-28 05:47:15356int ReadFile(const FilePath& filename, char* data, int size) {
357 int fd = open(filename.value().c_str(), O_RDONLY);
[email protected]b2e97292008-09-02 18:20:34358 if (fd < 0)
359 return -1;
[email protected]a9cd2a652008-11-17 21:01:19360
[email protected]b2e97292008-09-02 18:20:34361 int ret_value = read(fd, data, size);
362 close(fd);
363 return ret_value;
364}
365
[email protected]c870c762009-01-28 05:47:15366int WriteFile(const FilePath& filename, const char* data, int size) {
367 int fd = creat(filename.value().c_str(), 0666);
[email protected]b2e97292008-09-02 18:20:34368 if (fd < 0)
369 return -1;
[email protected]778e8c52008-09-11 17:36:23370
371 // Allow for partial writes
372 ssize_t bytes_written_total = 0;
373 do {
374 ssize_t bytes_written_partial = write(fd,
375 data + bytes_written_total,
376 size - bytes_written_total);
377 if (bytes_written_partial < 0) {
378 close(fd);
[email protected]a9cd2a652008-11-17 21:01:19379 return -1;
[email protected]778e8c52008-09-11 17:36:23380 }
381 bytes_written_total += bytes_written_partial;
382 } while (bytes_written_total < size);
383
[email protected]b2e97292008-09-02 18:20:34384 close(fd);
[email protected]778e8c52008-09-11 17:36:23385 return bytes_written_total;
[email protected]b2e97292008-09-02 18:20:34386}
387
388// Gets the current working directory for the process.
[email protected]640517f2008-10-30 23:54:04389bool GetCurrentDirectory(FilePath* dir) {
[email protected]b2e97292008-09-02 18:20:34390 char system_buffer[PATH_MAX] = "";
[email protected]640517f2008-10-30 23:54:04391 if (!getcwd(system_buffer, sizeof(system_buffer))) {
392 NOTREACHED();
393 return false;
394 }
395 *dir = FilePath(system_buffer);
[email protected]b2e97292008-09-02 18:20:34396 return true;
397}
398
399// Sets the current working directory for the process.
[email protected]a9cd2a652008-11-17 21:01:19400bool SetCurrentDirectory(const FilePath& path) {
401 int ret = chdir(path.value().c_str());
402 return !ret;
[email protected]b2e97292008-09-02 18:20:34403}
[email protected]a9cd2a652008-11-17 21:01:19404
[email protected]7856bb82008-12-12 23:43:03405///////////////////////////////////////////////
406// FileEnumerator
407
[email protected]0b733222008-12-11 14:55:12408FileEnumerator::FileEnumerator(const FilePath& root_path,
[email protected]b2e97292008-09-02 18:20:34409 bool recursive,
410 FileEnumerator::FILE_TYPE file_type)
411 : recursive_(recursive),
412 file_type_(file_type),
413 is_in_find_op_(false),
414 fts_(NULL) {
415 pending_paths_.push(root_path);
416}
417
[email protected]0b733222008-12-11 14:55:12418FileEnumerator::FileEnumerator(const FilePath& root_path,
[email protected]b2e97292008-09-02 18:20:34419 bool recursive,
420 FileEnumerator::FILE_TYPE file_type,
[email protected]0b733222008-12-11 14:55:12421 const FilePath::StringType& pattern)
[email protected]b2e97292008-09-02 18:20:34422 : recursive_(recursive),
423 file_type_(file_type),
[email protected]0b733222008-12-11 14:55:12424 pattern_(root_path.value()),
[email protected]b2e97292008-09-02 18:20:34425 is_in_find_op_(false),
426 fts_(NULL) {
427 // The Windows version of this code only matches against items in the top-most
428 // directory, and we're comparing fnmatch against full paths, so this is the
429 // easiest way to get the right pattern.
[email protected]0b733222008-12-11 14:55:12430 pattern_ = pattern_.Append(pattern);
[email protected]b2e97292008-09-02 18:20:34431 pending_paths_.push(root_path);
432}
[email protected]a9cd2a652008-11-17 21:01:19433
[email protected]b2e97292008-09-02 18:20:34434FileEnumerator::~FileEnumerator() {
435 if (fts_)
436 fts_close(fts_);
437}
438
[email protected]13ef7c02008-11-20 22:30:13439void FileEnumerator::GetFindInfo(FindInfo* info) {
440 DCHECK(info);
441
442 if (!is_in_find_op_)
443 return;
444
445 memcpy(&(info->stat), fts_ent_->fts_statp, sizeof(info->stat));
446 info->filename.assign(fts_ent_->fts_name);
447}
448
[email protected]b2e97292008-09-02 18:20:34449// As it stands, this method calls itself recursively when the next item of
450// the fts enumeration doesn't match (type, pattern, etc.). In the case of
451// large directories with many files this can be quite deep.
452// TODO(erikkay) - get rid of this recursive pattern
[email protected]0b733222008-12-11 14:55:12453FilePath FileEnumerator::Next() {
[email protected]b2e97292008-09-02 18:20:34454 if (!is_in_find_op_) {
455 if (pending_paths_.empty())
[email protected]0b733222008-12-11 14:55:12456 return FilePath();
[email protected]13ef7c02008-11-20 22:30:13457
[email protected]b2e97292008-09-02 18:20:34458 // The last find FindFirstFile operation is done, prepare a new one.
459 root_path_ = pending_paths_.top();
[email protected]0b733222008-12-11 14:55:12460 root_path_ = root_path_.StripTrailingSeparators();
[email protected]b2e97292008-09-02 18:20:34461 pending_paths_.pop();
[email protected]13ef7c02008-11-20 22:30:13462
[email protected]b2e97292008-09-02 18:20:34463 // Start a new find operation.
464 int ftsflags = FTS_LOGICAL;
465 char top_dir[PATH_MAX];
[email protected]e15c8e02009-01-02 12:57:53466 base::strlcpy(top_dir, root_path_.value().c_str(), arraysize(top_dir));
[email protected]b2e97292008-09-02 18:20:34467 char* dir_list[2] = { top_dir, NULL };
468 fts_ = fts_open(dir_list, ftsflags, NULL);
469 if (!fts_)
470 return Next();
471 is_in_find_op_ = true;
472 }
[email protected]13ef7c02008-11-20 22:30:13473
474 fts_ent_ = fts_read(fts_);
475 if (fts_ent_ == NULL) {
[email protected]b2e97292008-09-02 18:20:34476 fts_close(fts_);
477 fts_ = NULL;
478 is_in_find_op_ = false;
479 return Next();
480 }
[email protected]13ef7c02008-11-20 22:30:13481
[email protected]b2e97292008-09-02 18:20:34482 // Level 0 is the top, which is always skipped.
[email protected]13ef7c02008-11-20 22:30:13483 if (fts_ent_->fts_level == 0)
[email protected]b2e97292008-09-02 18:20:34484 return Next();
[email protected]13ef7c02008-11-20 22:30:13485
[email protected]b2e97292008-09-02 18:20:34486 // Patterns are only matched on the items in the top-most directory.
487 // (see Windows implementation)
[email protected]0b733222008-12-11 14:55:12488 if (fts_ent_->fts_level == 1 && pattern_.value().length() > 0) {
489 if (fnmatch(pattern_.value().c_str(), fts_ent_->fts_path, 0) != 0) {
[email protected]13ef7c02008-11-20 22:30:13490 if (fts_ent_->fts_info == FTS_D)
491 fts_set(fts_, fts_ent_, FTS_SKIP);
[email protected]b2e97292008-09-02 18:20:34492 return Next();
493 }
494 }
[email protected]13ef7c02008-11-20 22:30:13495
[email protected]0b733222008-12-11 14:55:12496 FilePath cur_file(fts_ent_->fts_path);
[email protected]13ef7c02008-11-20 22:30:13497 if (fts_ent_->fts_info == FTS_D) {
[email protected]b2e97292008-09-02 18:20:34498 // If not recursive, then prune children.
499 if (!recursive_)
[email protected]13ef7c02008-11-20 22:30:13500 fts_set(fts_, fts_ent_, FTS_SKIP);
[email protected]b2e97292008-09-02 18:20:34501 return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
[email protected]13ef7c02008-11-20 22:30:13502 } else if (fts_ent_->fts_info == FTS_F) {
[email protected]b2e97292008-09-02 18:20:34503 return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
504 }
505 // TODO(erikkay) - verify that the other fts_info types aren't interesting
506 return Next();
507}
[email protected]13ef7c02008-11-20 22:30:13508
[email protected]7856bb82008-12-12 23:43:03509///////////////////////////////////////////////
510// MemoryMappedFile
511
512MemoryMappedFile::MemoryMappedFile()
513 : file_(-1),
514 data_(NULL),
515 length_(0) {
516}
517
518bool MemoryMappedFile::MapFileToMemory(const FilePath& file_name) {
519 file_ = open(file_name.value().c_str(), O_RDONLY);
520 if (file_ == -1)
521 return false;
522
523 struct stat file_stat;
524 if (fstat(file_, &file_stat) == -1)
525 return false;
526 length_ = file_stat.st_size;
527
528 data_ = static_cast<uint8*>(
529 mmap(NULL, length_, PROT_READ, MAP_SHARED, file_, 0));
530 if (data_ == MAP_FAILED)
531 data_ = NULL;
532 return data_ != NULL;
533}
534
535void MemoryMappedFile::CloseHandles() {
536 if (data_ != NULL)
537 munmap(data_, length_);
538 if (file_ != -1)
539 close(file_);
540
541 data_ = NULL;
542 length_ = 0;
543 file_ = -1;
544}
[email protected]13ef7c02008-11-20 22:30:13545
[email protected]b2e97292008-09-02 18:20:34546} // namespace file_util