| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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> | |
| 11 #include <libgen.h> | 10 #include <libgen.h> |
| 12 #include <limits.h> | 11 #include <limits.h> |
| 13 #include <stdio.h> | 12 #include <stdio.h> |
| 14 #include <stdlib.h> | 13 #include <stdlib.h> |
| 15 #include <string.h> | 14 #include <string.h> |
| 16 #include <sys/errno.h> | 15 #include <sys/errno.h> |
| 17 #include <sys/mman.h> | 16 #include <sys/mman.h> |
| 18 #include <sys/param.h> | 17 #include <sys/param.h> |
| 19 #include <sys/stat.h> | 18 #include <sys/stat.h> |
| 20 #include <sys/time.h> | 19 #include <sys/time.h> |
| 21 #include <sys/types.h> | 20 #include <sys/types.h> |
| 22 #include <time.h> | 21 #include <time.h> |
| 23 #include <unistd.h> | 22 #include <unistd.h> |
| 24 | 23 |
| 25 #if defined(OS_MACOSX) | 24 #if defined(OS_MACOSX) |
| 26 #include <AvailabilityMacros.h> | 25 #include <AvailabilityMacros.h> |
| 27 #include "base/mac/foundation_util.h" | 26 #include "base/mac/foundation_util.h" |
| 28 #elif !defined(OS_ANDROID) | 27 #elif !defined(OS_ANDROID) |
| 29 #include <glib.h> | 28 #include <glib.h> |
| 30 #endif | 29 #endif |
| 31 | 30 |
| 32 #include <fstream> | 31 #include <fstream> |
| 33 | 32 |
| 34 #include "base/basictypes.h" | 33 #include "base/basictypes.h" |
| 34 #include "base/files/file_enumerator.h" |
| 35 #include "base/files/file_path.h" | 35 #include "base/files/file_path.h" |
| 36 #include "base/logging.h" | 36 #include "base/logging.h" |
| 37 #include "base/memory/scoped_ptr.h" | 37 #include "base/memory/scoped_ptr.h" |
| 38 #include "base/memory/singleton.h" | 38 #include "base/memory/singleton.h" |
| 39 #include "base/path_service.h" | 39 #include "base/path_service.h" |
| 40 #include "base/posix/eintr_wrapper.h" | 40 #include "base/posix/eintr_wrapper.h" |
| 41 #include "base/stl_util.h" | 41 #include "base/stl_util.h" |
| 42 #include "base/string_util.h" | 42 #include "base/string_util.h" |
| 43 #include "base/stringprintf.h" | 43 #include "base/stringprintf.h" |
| 44 #include "base/strings/sys_string_conversions.h" | 44 #include "base/strings/sys_string_conversions.h" |
| 45 #include "base/strings/utf_string_conversions.h" | 45 #include "base/strings/utf_string_conversions.h" |
| 46 #include "base/threading/thread_restrictions.h" | 46 #include "base/threading/thread_restrictions.h" |
| 47 #include "base/time.h" | 47 #include "base/time.h" |
| 48 | 48 |
| 49 #if defined(OS_ANDROID) | 49 #if defined(OS_ANDROID) |
| 50 #include "base/os_compat_android.h" | 50 #include "base/os_compat_android.h" |
| 51 #endif | 51 #endif |
| 52 | 52 |
| 53 #if !defined(OS_IOS) | 53 #if !defined(OS_IOS) |
| 54 #include <grp.h> | 54 #include <grp.h> |
| 55 #endif | 55 #endif |
| 56 | 56 |
| 57 #if defined(OS_CHROMEOS) | 57 #if defined(OS_CHROMEOS) |
| 58 #include "base/chromeos/chromeos_version.h" | 58 #include "base/chromeos/chromeos_version.h" |
| 59 #endif | 59 #endif |
| 60 | 60 |
| 61 using base::FileEnumerator; |
| 61 using base::FilePath; | 62 using base::FilePath; |
| 62 using base::MakeAbsoluteFilePath; | 63 using base::MakeAbsoluteFilePath; |
| 63 | 64 |
| 64 namespace base { | 65 namespace base { |
| 65 | 66 |
| 66 FilePath MakeAbsoluteFilePath(const FilePath& input) { | 67 FilePath MakeAbsoluteFilePath(const FilePath& input) { |
| 67 base::ThreadRestrictions::AssertIOAllowed(); | 68 base::ThreadRestrictions::AssertIOAllowed(); |
| 68 char full_path[PATH_MAX]; | 69 char full_path[PATH_MAX]; |
| 69 if (realpath(input.value().c_str(), full_path) == NULL) | 70 if (realpath(input.value().c_str(), full_path) == NULL) |
| 70 return FilePath(); | 71 return FilePath(); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 return (rmdir(path_str) == 0); | 184 return (rmdir(path_str) == 0); |
| 184 | 185 |
| 185 bool success = true; | 186 bool success = true; |
| 186 std::stack<std::string> directories; | 187 std::stack<std::string> directories; |
| 187 directories.push(path.value()); | 188 directories.push(path.value()); |
| 188 FileEnumerator traversal(path, true, | 189 FileEnumerator traversal(path, true, |
| 189 FileEnumerator::FILES | FileEnumerator::DIRECTORIES | | 190 FileEnumerator::FILES | FileEnumerator::DIRECTORIES | |
| 190 FileEnumerator::SHOW_SYM_LINKS); | 191 FileEnumerator::SHOW_SYM_LINKS); |
| 191 for (FilePath current = traversal.Next(); success && !current.empty(); | 192 for (FilePath current = traversal.Next(); success && !current.empty(); |
| 192 current = traversal.Next()) { | 193 current = traversal.Next()) { |
| 193 FileEnumerator::FindInfo info; | 194 if (traversal.GetInfo().IsDirectory()) |
| 194 traversal.GetFindInfo(&info); | |
| 195 | |
| 196 if (S_ISDIR(info.stat.st_mode)) | |
| 197 directories.push(current.value()); | 195 directories.push(current.value()); |
| 198 else | 196 else |
| 199 success = (unlink(current.value().c_str()) == 0); | 197 success = (unlink(current.value().c_str()) == 0); |
| 200 } | 198 } |
| 201 | 199 |
| 202 while (success && !directories.empty()) { | 200 while (success && !directories.empty()) { |
| 203 FilePath dir = FilePath(directories.top()); | 201 FilePath dir = FilePath(directories.top()); |
| 204 directories.pop(); | 202 directories.pop(); |
| 205 success = (rmdir(dir.value().c_str()) == 0); | 203 success = (rmdir(dir.value().c_str()) == 0); |
| 206 } | 204 } |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 return false; | 278 return false; |
| 281 | 279 |
| 282 bool success = true; | 280 bool success = true; |
| 283 int traverse_type = FileEnumerator::FILES | FileEnumerator::SHOW_SYM_LINKS; | 281 int traverse_type = FileEnumerator::FILES | FileEnumerator::SHOW_SYM_LINKS; |
| 284 if (recursive) | 282 if (recursive) |
| 285 traverse_type |= FileEnumerator::DIRECTORIES; | 283 traverse_type |= FileEnumerator::DIRECTORIES; |
| 286 FileEnumerator traversal(from_path, recursive, traverse_type); | 284 FileEnumerator traversal(from_path, recursive, traverse_type); |
| 287 | 285 |
| 288 // We have to mimic windows behavior here. |to_path| may not exist yet, | 286 // We have to mimic windows behavior here. |to_path| may not exist yet, |
| 289 // start the loop with |to_path|. | 287 // start the loop with |to_path|. |
| 290 FileEnumerator::FindInfo info; | 288 struct stat from_stat; |
| 291 FilePath current = from_path; | 289 FilePath current = from_path; |
| 292 if (stat(from_path.value().c_str(), &info.stat) < 0) { | 290 if (stat(from_path.value().c_str(), &from_stat) < 0) { |
| 293 DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: " | 291 DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: " |
| 294 << from_path.value() << " errno = " << errno; | 292 << from_path.value() << " errno = " << errno; |
| 295 success = false; | 293 success = false; |
| 296 } | 294 } |
| 297 struct stat to_path_stat; | 295 struct stat to_path_stat; |
| 298 FilePath from_path_base = from_path; | 296 FilePath from_path_base = from_path; |
| 299 if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 && | 297 if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 && |
| 300 S_ISDIR(to_path_stat.st_mode)) { | 298 S_ISDIR(to_path_stat.st_mode)) { |
| 301 // If the destination already exists and is a directory, then the | 299 // If the destination already exists and is a directory, then the |
| 302 // top level of source needs to be copied. | 300 // top level of source needs to be copied. |
| 303 from_path_base = from_path.DirName(); | 301 from_path_base = from_path.DirName(); |
| 304 } | 302 } |
| 305 | 303 |
| 306 // The Windows version of this function assumes that non-recursive calls | 304 // The Windows version of this function assumes that non-recursive calls |
| 307 // will always have a directory for from_path. | 305 // will always have a directory for from_path. |
| 308 DCHECK(recursive || S_ISDIR(info.stat.st_mode)); | 306 DCHECK(recursive || S_ISDIR(from_stat.st_mode)); |
| 309 | 307 |
| 310 while (success && !current.empty()) { | 308 while (success && !current.empty()) { |
| 311 // current is the source path, including from_path, so append | 309 // current is the source path, including from_path, so append |
| 312 // the suffix after from_path to to_path to create the target_path. | 310 // the suffix after from_path to to_path to create the target_path. |
| 313 FilePath target_path(to_path); | 311 FilePath target_path(to_path); |
| 314 if (from_path_base != current) { | 312 if (from_path_base != current) { |
| 315 if (!from_path_base.AppendRelativePath(current, &target_path)) { | 313 if (!from_path_base.AppendRelativePath(current, &target_path)) { |
| 316 success = false; | 314 success = false; |
| 317 break; | 315 break; |
| 318 } | 316 } |
| 319 } | 317 } |
| 320 | 318 |
| 321 if (S_ISDIR(info.stat.st_mode)) { | 319 if (S_ISDIR(from_stat.st_mode)) { |
| 322 if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 && | 320 if (mkdir(target_path.value().c_str(), from_stat.st_mode & 01777) != 0 && |
| 323 errno != EEXIST) { | 321 errno != EEXIST) { |
| 324 DLOG(ERROR) << "CopyDirectory() couldn't create directory: " | 322 DLOG(ERROR) << "CopyDirectory() couldn't create directory: " |
| 325 << target_path.value() << " errno = " << errno; | 323 << target_path.value() << " errno = " << errno; |
| 326 success = false; | 324 success = false; |
| 327 } | 325 } |
| 328 } else if (S_ISREG(info.stat.st_mode)) { | 326 } else if (S_ISREG(from_stat.st_mode)) { |
| 329 if (!CopyFile(current, target_path)) { | 327 if (!CopyFile(current, target_path)) { |
| 330 DLOG(ERROR) << "CopyDirectory() couldn't create file: " | 328 DLOG(ERROR) << "CopyDirectory() couldn't create file: " |
| 331 << target_path.value(); | 329 << target_path.value(); |
| 332 success = false; | 330 success = false; |
| 333 } | 331 } |
| 334 } else { | 332 } else { |
| 335 DLOG(WARNING) << "CopyDirectory() skipping non-regular file: " | 333 DLOG(WARNING) << "CopyDirectory() skipping non-regular file: " |
| 336 << current.value(); | 334 << current.value(); |
| 337 } | 335 } |
| 338 | 336 |
| 339 current = traversal.Next(); | 337 current = traversal.Next(); |
| 340 traversal.GetFindInfo(&info); | 338 if (!current.empty()) |
| 339 from_stat = traversal.GetInfo().stat(); |
| 341 } | 340 } |
| 342 | 341 |
| 343 return success; | 342 return success; |
| 344 } | 343 } |
| 345 | 344 |
| 346 bool PathExists(const FilePath& path) { | 345 bool PathExists(const FilePath& path) { |
| 347 base::ThreadRestrictions::AssertIOAllowed(); | 346 base::ThreadRestrictions::AssertIOAllowed(); |
| 348 return access(path.value().c_str(), F_OK) == 0; | 347 return access(path.value().c_str(), F_OK) == 0; |
| 349 } | 348 } |
| 350 | 349 |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 683 return true; | 682 return true; |
| 684 } | 683 } |
| 685 | 684 |
| 686 // Sets the current working directory for the process. | 685 // Sets the current working directory for the process. |
| 687 bool SetCurrentDirectory(const FilePath& path) { | 686 bool SetCurrentDirectory(const FilePath& path) { |
| 688 base::ThreadRestrictions::AssertIOAllowed(); | 687 base::ThreadRestrictions::AssertIOAllowed(); |
| 689 int ret = chdir(path.value().c_str()); | 688 int ret = chdir(path.value().c_str()); |
| 690 return !ret; | 689 return !ret; |
| 691 } | 690 } |
| 692 | 691 |
| 693 /////////////////////////////////////////////// | |
| 694 // FileEnumerator | |
| 695 | |
| 696 FileEnumerator::FileEnumerator(const FilePath& root_path, | |
| 697 bool recursive, | |
| 698 int file_type) | |
| 699 : current_directory_entry_(0), | |
| 700 root_path_(root_path), | |
| 701 recursive_(recursive), | |
| 702 file_type_(file_type) { | |
| 703 // INCLUDE_DOT_DOT must not be specified if recursive. | |
| 704 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); | |
| 705 pending_paths_.push(root_path); | |
| 706 } | |
| 707 | |
| 708 FileEnumerator::FileEnumerator(const FilePath& root_path, | |
| 709 bool recursive, | |
| 710 int file_type, | |
| 711 const FilePath::StringType& pattern) | |
| 712 : current_directory_entry_(0), | |
| 713 root_path_(root_path), | |
| 714 recursive_(recursive), | |
| 715 file_type_(file_type), | |
| 716 pattern_(root_path.Append(pattern).value()) { | |
| 717 // INCLUDE_DOT_DOT must not be specified if recursive. | |
| 718 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); | |
| 719 // The Windows version of this code appends the pattern to the root_path, | |
| 720 // potentially only matching against items in the top-most directory. | |
| 721 // Do the same here. | |
| 722 if (pattern.empty()) | |
| 723 pattern_ = FilePath::StringType(); | |
| 724 pending_paths_.push(root_path); | |
| 725 } | |
| 726 | |
| 727 FileEnumerator::~FileEnumerator() { | |
| 728 } | |
| 729 | |
| 730 FilePath FileEnumerator::Next() { | |
| 731 ++current_directory_entry_; | |
| 732 | |
| 733 // While we've exhausted the entries in the current directory, do the next | |
| 734 while (current_directory_entry_ >= directory_entries_.size()) { | |
| 735 if (pending_paths_.empty()) | |
| 736 return FilePath(); | |
| 737 | |
| 738 root_path_ = pending_paths_.top(); | |
| 739 root_path_ = root_path_.StripTrailingSeparators(); | |
| 740 pending_paths_.pop(); | |
| 741 | |
| 742 std::vector<DirectoryEntryInfo> entries; | |
| 743 if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS)) | |
| 744 continue; | |
| 745 | |
| 746 directory_entries_.clear(); | |
| 747 current_directory_entry_ = 0; | |
| 748 for (std::vector<DirectoryEntryInfo>::const_iterator | |
| 749 i = entries.begin(); i != entries.end(); ++i) { | |
| 750 FilePath full_path = root_path_.Append(i->filename); | |
| 751 if (ShouldSkip(full_path)) | |
| 752 continue; | |
| 753 | |
| 754 if (pattern_.size() && | |
| 755 fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE)) | |
| 756 continue; | |
| 757 | |
| 758 if (recursive_ && S_ISDIR(i->stat.st_mode)) | |
| 759 pending_paths_.push(full_path); | |
| 760 | |
| 761 if ((S_ISDIR(i->stat.st_mode) && (file_type_ & DIRECTORIES)) || | |
| 762 (!S_ISDIR(i->stat.st_mode) && (file_type_ & FILES))) | |
| 763 directory_entries_.push_back(*i); | |
| 764 } | |
| 765 } | |
| 766 | |
| 767 return root_path_.Append(directory_entries_[current_directory_entry_ | |
| 768 ].filename); | |
| 769 } | |
| 770 | |
| 771 void FileEnumerator::GetFindInfo(FindInfo* info) { | |
| 772 DCHECK(info); | |
| 773 | |
| 774 if (current_directory_entry_ >= directory_entries_.size()) | |
| 775 return; | |
| 776 | |
| 777 DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_]; | |
| 778 memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat)); | |
| 779 info->filename.assign(cur_entry->filename.value()); | |
| 780 } | |
| 781 | |
| 782 // static | |
| 783 bool FileEnumerator::IsDirectory(const FindInfo& info) { | |
| 784 return S_ISDIR(info.stat.st_mode); | |
| 785 } | |
| 786 | |
| 787 // static | |
| 788 FilePath FileEnumerator::GetFilename(const FindInfo& find_info) { | |
| 789 return FilePath(find_info.filename); | |
| 790 } | |
| 791 | |
| 792 // static | |
| 793 int64 FileEnumerator::GetFilesize(const FindInfo& find_info) { | |
| 794 return find_info.stat.st_size; | |
| 795 } | |
| 796 | |
| 797 // static | |
| 798 base::Time FileEnumerator::GetLastModifiedTime(const FindInfo& find_info) { | |
| 799 return base::Time::FromTimeT(find_info.stat.st_mtime); | |
| 800 } | |
| 801 | |
| 802 bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* entries, | |
| 803 const FilePath& source, bool show_links) { | |
| 804 base::ThreadRestrictions::AssertIOAllowed(); | |
| 805 DIR* dir = opendir(source.value().c_str()); | |
| 806 if (!dir) | |
| 807 return false; | |
| 808 | |
| 809 #if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_BSD) && \ | |
| 810 !defined(OS_SOLARIS) && !defined(OS_ANDROID) | |
| 811 #error Port warning: depending on the definition of struct dirent, \ | |
| 812 additional space for pathname may be needed | |
| 813 #endif | |
| 814 | |
| 815 struct dirent dent_buf; | |
| 816 struct dirent* dent; | |
| 817 while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) { | |
| 818 DirectoryEntryInfo info; | |
| 819 info.filename = FilePath(dent->d_name); | |
| 820 | |
| 821 FilePath full_name = source.Append(dent->d_name); | |
| 822 int ret; | |
| 823 if (show_links) | |
| 824 ret = lstat(full_name.value().c_str(), &info.stat); | |
| 825 else | |
| 826 ret = stat(full_name.value().c_str(), &info.stat); | |
| 827 if (ret < 0) { | |
| 828 // Print the stat() error message unless it was ENOENT and we're | |
| 829 // following symlinks. | |
| 830 if (!(errno == ENOENT && !show_links)) { | |
| 831 DPLOG(ERROR) << "Couldn't stat " | |
| 832 << source.Append(dent->d_name).value(); | |
| 833 } | |
| 834 memset(&info.stat, 0, sizeof(info.stat)); | |
| 835 } | |
| 836 entries->push_back(info); | |
| 837 } | |
| 838 | |
| 839 closedir(dir); | |
| 840 return true; | |
| 841 } | |
| 842 | |
| 843 bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) { | 692 bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) { |
| 844 FilePath real_path_result; | 693 FilePath real_path_result; |
| 845 if (!RealPath(path, &real_path_result)) | 694 if (!RealPath(path, &real_path_result)) |
| 846 return false; | 695 return false; |
| 847 | 696 |
| 848 // To be consistant with windows, fail if |real_path_result| is a | 697 // To be consistant with windows, fail if |real_path_result| is a |
| 849 // directory. | 698 // directory. |
| 850 stat_wrapper_t file_info; | 699 stat_wrapper_t file_info; |
| 851 if (CallStat(real_path_result.value().c_str(), &file_info) != 0 || | 700 if (CallStat(real_path_result.value().c_str(), &file_info) != 0 || |
| 852 S_ISDIR(file_info.st_mode)) | 701 S_ISDIR(file_info.st_mode)) |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1067 kFileSystemRoot, path, kRootUid, allowed_group_ids); | 916 kFileSystemRoot, path, kRootUid, allowed_group_ids); |
| 1068 } | 917 } |
| 1069 #endif // defined(OS_MACOSX) && !defined(OS_IOS) | 918 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
| 1070 | 919 |
| 1071 int GetMaximumPathComponentLength(const FilePath& path) { | 920 int GetMaximumPathComponentLength(const FilePath& path) { |
| 1072 base::ThreadRestrictions::AssertIOAllowed(); | 921 base::ThreadRestrictions::AssertIOAllowed(); |
| 1073 return pathconf(path.value().c_str(), _PC_NAME_MAX); | 922 return pathconf(path.value().c_str(), _PC_NAME_MAX); |
| 1074 } | 923 } |
| 1075 | 924 |
| 1076 } // namespace file_util | 925 } // namespace file_util |
| OLD | NEW |