Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(217)

Side by Side Diff: base/file_util_posix.cc

Issue 160479: Support files larger than 2GB (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/file_util.h ('k') | base/test_file_util_posix.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/file_util.h" 5 #include "base/file_util.h"
6 6
7 #include <dirent.h> 7 #include <dirent.h>
8 #include <errno.h> 8 #include <errno.h>
9 #include <fcntl.h> 9 #include <fcntl.h>
10 #include <fnmatch.h> 10 #include <fnmatch.h>
11 #include <fts.h>
12 #include <libgen.h> 11 #include <libgen.h>
13 #include <stdio.h> 12 #include <stdio.h>
14 #include <string.h> 13 #include <string.h>
15 #include <sys/errno.h> 14 #include <sys/errno.h>
16 #include <sys/mman.h> 15 #include <sys/mman.h>
17 #include <sys/stat.h> 16 #include <sys/stat.h>
18 #include <sys/types.h> 17 #include <sys/types.h>
19 #include <time.h> 18 #include <time.h>
20 #include <unistd.h> 19 #include <unistd.h>
21 20
22 #include <fstream> 21 #include <fstream>
23 22
24 #include "base/basictypes.h" 23 #include "base/basictypes.h"
25 #include "base/eintr_wrapper.h" 24 #include "base/eintr_wrapper.h"
26 #include "base/file_path.h" 25 #include "base/file_path.h"
27 #include "base/lock.h" 26 #include "base/lock.h"
28 #include "base/logging.h" 27 #include "base/logging.h"
29 #include "base/scoped_ptr.h" 28 #include "base/scoped_ptr.h"
30 #include "base/singleton.h" 29 #include "base/singleton.h"
31 #include "base/string_util.h" 30 #include "base/string_util.h"
32 #include "base/sys_string_conversions.h" 31 #include "base/sys_string_conversions.h"
33 #include "base/time.h" 32 #include "base/time.h"
34 #include "unicode/coll.h" 33 #include "unicode/coll.h"
35 34
36 namespace { 35 namespace {
37 36
38 bool IsDirectory(const FTSENT* file) {
39 switch (file->fts_info) {
40 case FTS_D:
41 case FTS_DC:
42 case FTS_DNR:
43 case FTS_DOT:
44 case FTS_DP:
45 return true;
46 default:
47 return false;
48 }
49 }
50
51 class LocaleAwareComparator { 37 class LocaleAwareComparator {
52 public: 38 public:
53 LocaleAwareComparator() { 39 LocaleAwareComparator() {
54 UErrorCode error_code = U_ZERO_ERROR; 40 UErrorCode error_code = U_ZERO_ERROR;
55 // Use the default collator. The default locale should have been properly 41 // Use the default collator. The default locale should have been properly
56 // set by the time this constructor is called. 42 // set by the time this constructor is called.
57 collator_.reset(Collator::createInstance(error_code)); 43 collator_.reset(Collator::createInstance(error_code));
58 DCHECK(U_SUCCESS(error_code)); 44 DCHECK(U_SUCCESS(error_code));
59 // Make it case-sensitive. 45 // Make it case-sensitive.
60 collator_->setStrength(Collator::TERTIARY); 46 collator_->setStrength(Collator::TERTIARY);
(...skipping 24 matching lines...) Expand all
85 } 71 }
86 72
87 private: 73 private:
88 scoped_ptr<Collator> collator_; 74 scoped_ptr<Collator> collator_;
89 Lock lock_; 75 Lock lock_;
90 friend struct DefaultSingletonTraits<LocaleAwareComparator>; 76 friend struct DefaultSingletonTraits<LocaleAwareComparator>;
91 77
92 DISALLOW_COPY_AND_ASSIGN(LocaleAwareComparator); 78 DISALLOW_COPY_AND_ASSIGN(LocaleAwareComparator);
93 }; 79 };
94 80
95 int CompareFiles(const FTSENT** a, const FTSENT** b) {
96 // Order lexicographically with directories before other files.
97 const bool a_is_dir = IsDirectory(*a);
98 const bool b_is_dir = IsDirectory(*b);
99 if (a_is_dir != b_is_dir)
100 return a_is_dir ? -1 : 1;
101
102 // On linux, the file system encoding is not defined. We assume
103 // SysNativeMBToWide takes care of it.
104 //
105 // ICU's collator can take strings in OS native encoding. But we convert the
106 // strings to UTF-16 ourselves to ensure conversion consistency.
107 // TODO(yuzo): Perhaps we should define SysNativeMBToUTF16?
108 return Singleton<LocaleAwareComparator>()->Compare(
109 WideToUTF16(base::SysNativeMBToWide((*a)->fts_name)),
110 WideToUTF16(base::SysNativeMBToWide((*b)->fts_name)));
111 }
112
113 } // namespace 81 } // namespace
114 82
115 namespace file_util { 83 namespace file_util {
116 84
117 #if defined(GOOGLE_CHROME_BUILD) 85 #if defined(GOOGLE_CHROME_BUILD)
118 static const char* kTempFileName = "com.google.chrome.XXXXXX"; 86 static const char* kTempFileName = "com.google.chrome.XXXXXX";
119 #else 87 #else
120 static const char* kTempFileName = "org.chromium.XXXXXX"; 88 static const char* kTempFileName = "org.chromium.XXXXXX";
121 #endif 89 #endif
122 90
(...skipping 16 matching lines...) Expand all
139 *path = FilePath(full_path); 107 *path = FilePath(full_path);
140 return true; 108 return true;
141 } 109 }
142 110
143 int CountFilesCreatedAfter(const FilePath& path, 111 int CountFilesCreatedAfter(const FilePath& path,
144 const base::Time& comparison_time) { 112 const base::Time& comparison_time) {
145 int file_count = 0; 113 int file_count = 0;
146 114
147 DIR* dir = opendir(path.value().c_str()); 115 DIR* dir = opendir(path.value().c_str());
148 if (dir) { 116 if (dir) {
117 #if !defined(OS_LINUX) && !defined(OS_MACOSX)
118 #error Depending on the definition of struct dirent, additional space for \
119 pathname may be needed
120 #endif
149 struct dirent ent_buf; 121 struct dirent ent_buf;
150 struct dirent* ent; 122 struct dirent* ent;
151 while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) { 123 while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) {
152 if ((strcmp(ent->d_name, ".") == 0) || 124 if ((strcmp(ent->d_name, ".") == 0) ||
153 (strcmp(ent->d_name, "..") == 0)) 125 (strcmp(ent->d_name, "..") == 0))
154 continue; 126 continue;
155 127
156 struct stat64 st; 128 struct stat64 st;
157 int test = stat64(path.Append(ent->d_name).value().c_str(), &st); 129 int test = stat64(path.Append(ent->d_name).value().c_str(), &st);
158 if (test != 0) { 130 if (test != 0) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 // The Windows version defines this condition as success. 166 // The Windows version defines this condition as success.
195 bool ret = (errno == ENOENT || errno == ENOTDIR); 167 bool ret = (errno == ENOENT || errno == ENOTDIR);
196 return ret; 168 return ret;
197 } 169 }
198 if (!S_ISDIR(file_info.st_mode)) 170 if (!S_ISDIR(file_info.st_mode))
199 return (unlink(path_str) == 0); 171 return (unlink(path_str) == 0);
200 if (!recursive) 172 if (!recursive)
201 return (rmdir(path_str) == 0); 173 return (rmdir(path_str) == 0);
202 174
203 bool success = true; 175 bool success = true;
204 int ftsflags = FTS_PHYSICAL | FTS_NOSTAT; 176 std::stack<std::string> directories;
205 char top_dir[PATH_MAX]; 177 directories.push(path.value());
206 if (base::strlcpy(top_dir, path_str, 178 FileEnumerator traversal(path, true, static_cast<FileEnumerator::FILE_TYPE>(
207 arraysize(top_dir)) >= arraysize(top_dir)) { 179 FileEnumerator::FILES | FileEnumerator::DIRECTORIES |
208 return false; 180 FileEnumerator::SHOW_SYM_LINKS));
181 for (FilePath current = traversal.Next(); success && !current.empty();
182 current = traversal.Next()) {
183 FileEnumerator::FindInfo info;
184 traversal.GetFindInfo(&info);
185
186 if (S_ISDIR(info.stat.st_mode))
187 directories.push(current.value());
188 else
189 success = (unlink(current.value().c_str()) == 0);
209 } 190 }
210 char* dir_list[2] = { top_dir, NULL }; 191
211 FTS* fts = fts_open(dir_list, ftsflags, NULL); 192 while (success && !directories.empty()) {
212 if (fts) { 193 FilePath dir = FilePath(directories.top());
213 FTSENT* fts_ent = fts_read(fts); 194 directories.pop();
214 while (success && fts_ent != NULL) { 195 success = (rmdir(dir.value().c_str()) == 0);
215 switch (fts_ent->fts_info) {
216 case FTS_DNR:
217 case FTS_ERR:
218 // log error
219 success = false;
220 continue;
221 break;
222 case FTS_DP:
223 success = (rmdir(fts_ent->fts_accpath) == 0);
224 break;
225 case FTS_D:
226 break;
227 case FTS_NSOK:
228 case FTS_F:
229 case FTS_SL:
230 case FTS_SLNONE:
231 success = (unlink(fts_ent->fts_accpath) == 0);
232 break;
233 default:
234 DCHECK(false);
235 break;
236 }
237 fts_ent = fts_read(fts);
238 }
239 fts_close(fts);
240 } 196 }
197
241 return success; 198 return success;
242 } 199 }
243 200
244 bool Move(const FilePath& from_path, const FilePath& to_path) { 201 bool Move(const FilePath& from_path, const FilePath& to_path) {
245 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) 202 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
246 return true; 203 return true;
247 204
248 if (!CopyDirectory(from_path, to_path, true)) 205 if (!CopyDirectory(from_path, to_path, true))
249 return false; 206 return false;
250 207
(...skipping 14 matching lines...) Expand all
265 // TODO(evanm): remove this once we're sure it's ok. 222 // TODO(evanm): remove this once we're sure it's ok.
266 DCHECK(to_path.value().find('*') == std::string::npos); 223 DCHECK(to_path.value().find('*') == std::string::npos);
267 DCHECK(from_path.value().find('*') == std::string::npos); 224 DCHECK(from_path.value().find('*') == std::string::npos);
268 225
269 char top_dir[PATH_MAX]; 226 char top_dir[PATH_MAX];
270 if (base::strlcpy(top_dir, from_path.value().c_str(), 227 if (base::strlcpy(top_dir, from_path.value().c_str(),
271 arraysize(top_dir)) >= arraysize(top_dir)) { 228 arraysize(top_dir)) >= arraysize(top_dir)) {
272 return false; 229 return false;
273 } 230 }
274 231
275 char* dir_list[] = { top_dir, NULL }; 232 // This function does not properly handle destinations within the source
276 FTS* fts = fts_open(dir_list, FTS_PHYSICAL | FTS_NOSTAT, NULL); 233 FilePath real_to_path = to_path;
277 if (!fts) { 234 if (PathExists(real_to_path)) {
278 LOG(ERROR) << "fts_open failed: " << strerror(errno); 235 if (!AbsolutePath(&real_to_path))
236 return false;
237 } else {
238 real_to_path = real_to_path.DirName();
239 if (!AbsolutePath(&real_to_path))
240 return false;
241 }
242 FilePath real_from_path = from_path;
243 if (!AbsolutePath(&real_from_path))
279 return false; 244 return false;
245 if (real_to_path.value().size() >= real_from_path.value().size() &&
246 real_to_path.value().compare(0, real_from_path.value().size(),
247 real_from_path.value()) == 0)
248 return false;
249
250 bool success = true;
251 FileEnumerator::FILE_TYPE traverse_type =
252 static_cast<FileEnumerator::FILE_TYPE>(FileEnumerator::FILES |
253 FileEnumerator::SHOW_SYM_LINKS);
254 if (recursive)
255 traverse_type = static_cast<FileEnumerator::FILE_TYPE>(
256 traverse_type | FileEnumerator::DIRECTORIES);
257 FileEnumerator traversal(from_path, recursive, traverse_type);
258
259 // to_path may not exist yet, start the loop with to_path
260 FileEnumerator::FindInfo info;
261 FilePath current = from_path;
262 if (stat(from_path.value().c_str(), &info.stat) < 0) {
263 LOG(ERROR) << "CopyDirectory() couldn't stat source directory: " <<
264 from_path.value() << " errno = " << errno;
265 success = false;
280 } 266 }
281 267
282 int error = 0; 268 while (success && !current.empty()) {
283 FTSENT* ent; 269 // current is the source path, including from_path, so paste
284 while (!error && (ent = fts_read(fts)) != NULL) {
285 // ent->fts_path is the source path, including from_path, so paste
286 // the suffix after from_path onto to_path to create the target_path. 270 // the suffix after from_path onto to_path to create the target_path.
287 std::string suffix(&ent->fts_path[from_path.value().size()]); 271 std::string suffix(&current.value().c_str()[from_path.value().size()]);
288 // Strip the leading '/' (if any). 272 // Strip the leading '/' (if any).
289 if (!suffix.empty()) { 273 if (!suffix.empty()) {
290 DCHECK_EQ('/', suffix[0]); 274 DCHECK_EQ('/', suffix[0]);
291 suffix.erase(0, 1); 275 suffix.erase(0, 1);
292 } 276 }
293 const FilePath target_path = to_path.Append(suffix); 277 const FilePath target_path = to_path.Append(suffix);
294 switch (ent->fts_info) {
295 case FTS_D: // Preorder directory.
296 // If we encounter a subdirectory in a non-recursive copy, prune it
297 // from the traversal.
298 if (!recursive && ent->fts_level > 0) {
299 if (fts_set(fts, ent, FTS_SKIP) != 0)
300 error = errno;
301 continue;
302 }
303 278
304 // Try creating the target dir, continuing on it if it exists already. 279 if (S_ISDIR(info.stat.st_mode)) {
305 if (mkdir(target_path.value().c_str(), 0700) != 0) { 280 if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
306 if (errno != EEXIST) 281 errno != EEXIST) {
307 error = errno; 282 LOG(ERROR) << "CopyDirectory() couldn't create directory: " <<
308 } 283 target_path.value() << " errno = " << errno;
309 break; 284 success = false;
310 case FTS_F: // Regular file. 285 }
311 case FTS_NSOK: // File, no stat info requested. 286 } else if (S_ISREG(info.stat.st_mode)) {
312 errno = 0; 287 if (!CopyFile(current, target_path)) {
313 if (!CopyFile(FilePath(ent->fts_path), target_path)) 288 LOG(ERROR) << "CopyDirectory() couldn't create file: " <<
314 error = errno ? errno : EINVAL; 289 target_path.value();
315 break; 290 success = false;
316 case FTS_DP: // Postorder directory. 291 }
317 case FTS_DOT: // "." or ".." 292 } else {
318 // Skip it. 293 LOG(WARNING) << "CopyDirectory() skipping non-regular file: " <<
319 continue; 294 current.value();
320 case FTS_DC: // Directory causing a cycle.
321 // Skip this branch.
322 if (fts_set(fts, ent, FTS_SKIP) != 0)
323 error = errno;
324 break;
325 case FTS_DNR: // Directory cannot be read.
326 case FTS_ERR: // Error.
327 case FTS_NS: // Stat failed.
328 // Abort with the error.
329 error = ent->fts_errno;
330 break;
331 case FTS_SL: // Symlink.
332 case FTS_SLNONE: // Symlink with broken target.
333 LOG(WARNING) << "CopyDirectory() skipping symbolic link: " <<
334 ent->fts_path;
335 continue;
336 case FTS_DEFAULT: // Some other sort of file.
337 LOG(WARNING) << "CopyDirectory() skipping file of unknown type: " <<
338 ent->fts_path;
339 continue;
340 default:
341 NOTREACHED();
342 continue; // Hope for the best!
343 } 295 }
344 }
345 // fts_read may have returned NULL and set errno to indicate an error.
346 if (!error && errno != 0)
347 error = errno;
348 296
349 if (!fts_close(fts)) { 297 current = traversal.Next();
350 // If we already have an error, let's use that error instead of the error 298 traversal.GetFindInfo(&info);
351 // fts_close set.
352 if (!error)
353 error = errno;
354 } 299 }
355 300
356 if (error) { 301 return success;
357 LOG(ERROR) << "CopyDirectory(): " << strerror(error);
358 return false;
359 }
360 return true;
361 } 302 }
362 303
363 bool PathExists(const FilePath& path) { 304 bool PathExists(const FilePath& path) {
364 struct stat64 file_info; 305 struct stat64 file_info;
365 return (stat64(path.value().c_str(), &file_info) == 0); 306 return (stat64(path.value().c_str(), &file_info) == 0);
366 } 307 }
367 308
368 bool PathIsWritable(const FilePath& path) { 309 bool PathIsWritable(const FilePath& path) {
369 FilePath test_path(path); 310 FilePath test_path(path);
370 struct stat64 file_info; 311 struct stat64 file_info;
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 int ret = chdir(path.value().c_str()); 536 int ret = chdir(path.value().c_str());
596 return !ret; 537 return !ret;
597 } 538 }
598 539
599 /////////////////////////////////////////////// 540 ///////////////////////////////////////////////
600 // FileEnumerator 541 // FileEnumerator
601 542
602 FileEnumerator::FileEnumerator(const FilePath& root_path, 543 FileEnumerator::FileEnumerator(const FilePath& root_path,
603 bool recursive, 544 bool recursive,
604 FileEnumerator::FILE_TYPE file_type) 545 FileEnumerator::FILE_TYPE file_type)
605 : recursive_(recursive), 546 : root_path_(root_path),
547 recursive_(recursive),
606 file_type_(file_type), 548 file_type_(file_type),
607 is_in_find_op_(false), 549 is_in_find_op_(false),
608 fts_(NULL) { 550 current_directory_entry_(0) {
609 // INCLUDE_DOT_DOT must not be specified if recursive. 551 // INCLUDE_DOT_DOT must not be specified if recursive.
610 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); 552 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
611 pending_paths_.push(root_path); 553 pending_paths_.push(root_path);
612 } 554 }
613 555
614 FileEnumerator::FileEnumerator(const FilePath& root_path, 556 FileEnumerator::FileEnumerator(const FilePath& root_path,
615 bool recursive, 557 bool recursive,
616 FileEnumerator::FILE_TYPE file_type, 558 FileEnumerator::FILE_TYPE file_type,
617 const FilePath::StringType& pattern) 559 const FilePath::StringType& pattern)
618 : recursive_(recursive), 560 : root_path_(root_path),
561 recursive_(recursive),
619 file_type_(file_type), 562 file_type_(file_type),
620 pattern_(root_path.value()), 563 pattern_(root_path.Append(pattern)),
621 is_in_find_op_(false), 564 is_in_find_op_(false),
622 fts_(NULL) { 565 current_directory_entry_(0) {
623 // INCLUDE_DOT_DOT must not be specified if recursive. 566 // INCLUDE_DOT_DOT must not be specified if recursive.
624 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); 567 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
625 // The Windows version of this code only matches against items in the top-most 568 // The Windows version of this code appends the pattern to the root_path,
626 // directory, and we're comparing fnmatch against full paths, so this is the 569 // potentially only matching against items in the top-most directory.
627 // easiest way to get the right pattern. 570 // Do the same here.
628 pattern_ = pattern_.Append(pattern); 571 if (pattern.size() == 0)
572 pattern_ = FilePath();
629 pending_paths_.push(root_path); 573 pending_paths_.push(root_path);
630 } 574 }
631 575
632 FileEnumerator::~FileEnumerator() { 576 FileEnumerator::~FileEnumerator() {
633 if (fts_)
634 fts_close(fts_);
635 } 577 }
636 578
637 void FileEnumerator::GetFindInfo(FindInfo* info) { 579 void FileEnumerator::GetFindInfo(FindInfo* info) {
638 DCHECK(info); 580 DCHECK(info);
639 581
640 if (!is_in_find_op_) 582 if (current_directory_entry_ >= directory_entries_.size())
641 return; 583 return;
642 584
643 memcpy(&(info->stat), fts_ent_->fts_statp, sizeof(info->stat)); 585 DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_];
644 info->filename.assign(fts_ent_->fts_name); 586 memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat));
587 info->filename.assign(cur_entry->filename.value());
645 } 588 }
646 589
647 // As it stands, this method calls itself recursively when the next item of
648 // the fts enumeration doesn't match (type, pattern, etc.). In the case of
649 // large directories with many files this can be quite deep.
650 // TODO(erikkay) - get rid of this recursive pattern
651 FilePath FileEnumerator::Next() { 590 FilePath FileEnumerator::Next() {
652 if (!is_in_find_op_) { 591 ++current_directory_entry_;
592
593 // While we've exhausted the entries in the current directory, do the next
594 while (current_directory_entry_ >= directory_entries_.size()) {
653 if (pending_paths_.empty()) 595 if (pending_paths_.empty())
654 return FilePath(); 596 return FilePath();
655 597
656 // The last find FindFirstFile operation is done, prepare a new one.
657 root_path_ = pending_paths_.top(); 598 root_path_ = pending_paths_.top();
658 root_path_ = root_path_.StripTrailingSeparators(); 599 root_path_ = root_path_.StripTrailingSeparators();
659 pending_paths_.pop(); 600 pending_paths_.pop();
660 601
661 // Start a new find operation. 602 std::vector<DirectoryEntryInfo> entries;
662 int ftsflags = FTS_LOGICAL | FTS_SEEDOT; 603 if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS))
663 char top_dir[PATH_MAX]; 604 continue;
664 base::strlcpy(top_dir, root_path_.value().c_str(), arraysize(top_dir));
665 char* dir_list[2] = { top_dir, NULL };
666 fts_ = fts_open(dir_list, ftsflags, CompareFiles);
667 if (!fts_)
668 return Next();
669 is_in_find_op_ = true;
670 }
671 605
672 fts_ent_ = fts_read(fts_); 606 // The API says that order is not guaranteed, but order affects UX
673 if (fts_ent_ == NULL) { 607 std::sort(entries.begin(), entries.end(), CompareFiles);
674 fts_close(fts_);
675 fts_ = NULL;
676 is_in_find_op_ = false;
677 return Next();
678 }
679 608
680 // Level 0 is the top, which is always skipped. 609 directory_entries_.clear();
681 if (fts_ent_->fts_level == 0) 610 current_directory_entry_ = 0;
682 return Next(); 611 for (std::vector<DirectoryEntryInfo>::const_iterator
612 i = entries.begin(); i != entries.end(); ++i) {
613 FilePath full_path = root_path_.Append(i->filename);
614 if (ShouldSkip(full_path))
615 continue;
683 616
684 // Patterns are only matched on the items in the top-most directory. 617 if (pattern_.value().size() &&
685 // (see Windows implementation) 618 fnmatch(pattern_.value().c_str(), full_path.value().c_str(),
686 if (fts_ent_->fts_level == 1 && pattern_.value().length() > 0) { 619 FNM_NOESCAPE))
687 if (fnmatch(pattern_.value().c_str(), fts_ent_->fts_path, 0) != 0) { 620 continue;
688 if (fts_ent_->fts_info == FTS_D) 621
689 fts_set(fts_, fts_ent_, FTS_SKIP); 622 if (recursive_ && S_ISDIR(i->stat.st_mode))
690 return Next(); 623 pending_paths_.push(full_path);
624
625 if ((S_ISDIR(i->stat.st_mode) && (file_type_ & DIRECTORIES)) ||
626 (!S_ISDIR(i->stat.st_mode) && (file_type_ & FILES)))
627 directory_entries_.push_back(*i);
691 } 628 }
692 } 629 }
693 630
694 FilePath cur_file(fts_ent_->fts_path); 631 return root_path_.Append(directory_entries_[current_directory_entry_
695 if (ShouldSkip(cur_file)) 632 ].filename);
696 return Next(); 633 }
697 634
698 if (fts_ent_->fts_info == FTS_D) { 635 bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* entries,
699 // If not recursive, then prune children. 636 const FilePath& source, bool show_links) {
700 if (!recursive_) 637 DIR* dir = opendir(source.value().c_str());
701 fts_set(fts_, fts_ent_, FTS_SKIP); 638 if (!dir)
702 return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next(); 639 return false;
703 } else if (fts_ent_->fts_info == FTS_F) { 640
704 return (file_type_ & FileEnumerator::FILES) ? cur_file : Next(); 641 #if !defined(OS_LINUX) && !defined(OS_MACOSX)
705 } else if (fts_ent_->fts_info == FTS_DOT) { 642 #error Depending on the definition of struct dirent, additional space for \
706 if ((file_type_ & FileEnumerator::DIRECTORIES) && IsDotDot(cur_file)) { 643 pathname may be needed
707 return cur_file; 644 #endif
645 struct dirent dent_buf;
646 struct dirent* dent;
647 while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) {
648 DirectoryEntryInfo info;
649 FilePath full_name;
650 int stat_value;
651
652 info.filename = FilePath(dent->d_name);
653 full_name = source.Append(dent->d_name);
654 if (show_links)
655 stat_value = lstat(full_name.value().c_str(), &info.stat);
656 else
657 stat_value = stat(full_name.value().c_str(), &info.stat);
658 if (stat_value < 0) {
659 LOG(ERROR) << "Couldn't stat file: " <<
660 source.Append(dent->d_name).value().c_str() << " errno = " << errno;
661 memset(&info.stat, 0, sizeof(info.stat));
708 } 662 }
709 return Next(); 663 entries->push_back(info);
710 } 664 }
711 // TODO(erikkay) - verify that the other fts_info types aren't interesting 665
712 return Next(); 666 closedir(dir);
667 return true;
668 }
669
670 bool FileEnumerator::CompareFiles(const DirectoryEntryInfo& a,
671 const DirectoryEntryInfo& b) {
672 // Order lexicographically with directories before other files.
673 if (S_ISDIR(a.stat.st_mode) != S_ISDIR(b.stat.st_mode))
674 return S_ISDIR(a.stat.st_mode);
675
676 // On linux, the file system encoding is not defined. We assume
677 // SysNativeMBToWide takes care of it.
678 //
679 // ICU's collator can take strings in OS native encoding. But we convert the
680 // strings to UTF-16 ourselves to ensure conversion consistency.
681 // TODO(yuzo): Perhaps we should define SysNativeMBToUTF16?
682 return Singleton<LocaleAwareComparator>()->Compare(
683 WideToUTF16(base::SysNativeMBToWide(a.filename.value().c_str())),
684 WideToUTF16(base::SysNativeMBToWide(b.filename.value().c_str()))) < 0;
713 } 685 }
714 686
715 /////////////////////////////////////////////// 687 ///////////////////////////////////////////////
716 // MemoryMappedFile 688 // MemoryMappedFile
717 689
718 MemoryMappedFile::MemoryMappedFile() 690 MemoryMappedFile::MemoryMappedFile()
719 : file_(-1), 691 : file_(-1),
720 data_(NULL), 692 data_(NULL),
721 length_(0) { 693 length_(0) {
722 } 694 }
(...skipping 26 matching lines...) Expand all
749 munmap(data_, length_); 721 munmap(data_, length_);
750 if (file_ != -1) 722 if (file_ != -1)
751 close(file_); 723 close(file_);
752 724
753 data_ = NULL; 725 data_ = NULL;
754 length_ = 0; 726 length_ = 0;
755 file_ = -1; 727 file_ = -1;
756 } 728 }
757 729
758 } // namespace file_util 730 } // namespace file_util
OLDNEW
« no previous file with comments | « base/file_util.h ('k') | base/test_file_util_posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698