| 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 <libgen.h> | 10 #include <libgen.h> |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 } | 190 } |
| 191 | 191 |
| 192 while (success && !directories.empty()) { | 192 while (success && !directories.empty()) { |
| 193 FilePath dir = FilePath(directories.top()); | 193 FilePath dir = FilePath(directories.top()); |
| 194 directories.pop(); | 194 directories.pop(); |
| 195 success = (rmdir(dir.value().c_str()) == 0); | 195 success = (rmdir(dir.value().c_str()) == 0); |
| 196 } | 196 } |
| 197 return success; | 197 return success; |
| 198 } | 198 } |
| 199 | 199 |
| 200 bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) { | |
| 201 ThreadRestrictions::AssertIOAllowed(); | |
| 202 // Windows compatibility: if to_path exists, from_path and to_path | |
| 203 // must be the same type, either both files, or both directories. | |
| 204 stat_wrapper_t to_file_info; | |
| 205 if (CallStat(to_path.value().c_str(), &to_file_info) == 0) { | |
| 206 stat_wrapper_t from_file_info; | |
| 207 if (CallStat(from_path.value().c_str(), &from_file_info) == 0) { | |
| 208 if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode)) | |
| 209 return false; | |
| 210 } else { | |
| 211 return false; | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) | |
| 216 return true; | |
| 217 | |
| 218 if (!file_util::CopyDirectory(from_path, to_path, true)) | |
| 219 return false; | |
| 220 | |
| 221 Delete(from_path, true); | |
| 222 return true; | |
| 223 } | |
| 224 | |
| 225 bool ReplaceFile(const FilePath& from_path, | 200 bool ReplaceFile(const FilePath& from_path, |
| 226 const FilePath& to_path, | 201 const FilePath& to_path, |
| 227 PlatformFileError* error) { | 202 PlatformFileError* error) { |
| 228 ThreadRestrictions::AssertIOAllowed(); | 203 ThreadRestrictions::AssertIOAllowed(); |
| 229 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) | 204 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) |
| 230 return true; | 205 return true; |
| 231 if (error) | 206 if (error) |
| 232 *error = ErrnoToPlatformFileError(errno); | 207 *error = ErrnoToPlatformFileError(errno); |
| 233 return false; | 208 return false; |
| 234 } | 209 } |
| 235 | 210 |
| 236 } // namespace base | |
| 237 | |
| 238 // ----------------------------------------------------------------------------- | |
| 239 | |
| 240 namespace file_util { | |
| 241 | |
| 242 using base::stat_wrapper_t; | |
| 243 using base::CallStat; | |
| 244 using base::CallLstat; | |
| 245 using base::FileEnumerator; | |
| 246 using base::FilePath; | |
| 247 using base::MakeAbsoluteFilePath; | |
| 248 using base::RealPath; | |
| 249 using base::VerifySpecificPathControlledByUser; | |
| 250 | |
| 251 bool CopyDirectory(const FilePath& from_path, | 211 bool CopyDirectory(const FilePath& from_path, |
| 252 const FilePath& to_path, | 212 const FilePath& to_path, |
| 253 bool recursive) { | 213 bool recursive) { |
| 254 base::ThreadRestrictions::AssertIOAllowed(); | 214 ThreadRestrictions::AssertIOAllowed(); |
| 255 // Some old callers of CopyDirectory want it to support wildcards. | 215 // Some old callers of CopyDirectory want it to support wildcards. |
| 256 // After some discussion, we decided to fix those callers. | 216 // After some discussion, we decided to fix those callers. |
| 257 // Break loudly here if anyone tries to do this. | 217 // Break loudly here if anyone tries to do this. |
| 258 // TODO(evanm): remove this once we're sure it's ok. | 218 // TODO(evanm): remove this once we're sure it's ok. |
| 259 DCHECK(to_path.value().find('*') == std::string::npos); | 219 DCHECK(to_path.value().find('*') == std::string::npos); |
| 260 DCHECK(from_path.value().find('*') == std::string::npos); | 220 DCHECK(from_path.value().find('*') == std::string::npos); |
| 261 | 221 |
| 262 char top_dir[PATH_MAX]; | 222 char top_dir[PATH_MAX]; |
| 263 if (base::strlcpy(top_dir, from_path.value().c_str(), | 223 if (strlcpy(top_dir, from_path.value().c_str(), |
| 264 arraysize(top_dir)) >= arraysize(top_dir)) { | 224 arraysize(top_dir)) >= arraysize(top_dir)) { |
| 265 return false; | 225 return false; |
| 266 } | 226 } |
| 267 | 227 |
| 268 // This function does not properly handle destinations within the source | 228 // This function does not properly handle destinations within the source |
| 269 FilePath real_to_path = to_path; | 229 FilePath real_to_path = to_path; |
| 270 if (PathExists(real_to_path)) { | 230 if (file_util::PathExists(real_to_path)) { |
| 271 real_to_path = MakeAbsoluteFilePath(real_to_path); | 231 real_to_path = MakeAbsoluteFilePath(real_to_path); |
| 272 if (real_to_path.empty()) | 232 if (real_to_path.empty()) |
| 273 return false; | 233 return false; |
| 274 } else { | 234 } else { |
| 275 real_to_path = MakeAbsoluteFilePath(real_to_path.DirName()); | 235 real_to_path = MakeAbsoluteFilePath(real_to_path.DirName()); |
| 276 if (real_to_path.empty()) | 236 if (real_to_path.empty()) |
| 277 return false; | 237 return false; |
| 278 } | 238 } |
| 279 FilePath real_from_path = MakeAbsoluteFilePath(from_path); | 239 FilePath real_from_path = MakeAbsoluteFilePath(from_path); |
| 280 if (real_from_path.empty()) | 240 if (real_from_path.empty()) |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 } | 302 } |
| 343 | 303 |
| 344 current = traversal.Next(); | 304 current = traversal.Next(); |
| 345 if (!current.empty()) | 305 if (!current.empty()) |
| 346 from_stat = traversal.GetInfo().stat(); | 306 from_stat = traversal.GetInfo().stat(); |
| 347 } | 307 } |
| 348 | 308 |
| 349 return success; | 309 return success; |
| 350 } | 310 } |
| 351 | 311 |
| 312 } // namespace base |
| 313 |
| 314 // ----------------------------------------------------------------------------- |
| 315 |
| 316 namespace file_util { |
| 317 |
| 318 using base::stat_wrapper_t; |
| 319 using base::CallStat; |
| 320 using base::CallLstat; |
| 321 using base::FileEnumerator; |
| 322 using base::FilePath; |
| 323 using base::MakeAbsoluteFilePath; |
| 324 using base::RealPath; |
| 325 using base::VerifySpecificPathControlledByUser; |
| 326 |
| 352 bool PathExists(const FilePath& path) { | 327 bool PathExists(const FilePath& path) { |
| 353 base::ThreadRestrictions::AssertIOAllowed(); | 328 base::ThreadRestrictions::AssertIOAllowed(); |
| 354 return access(path.value().c_str(), F_OK) == 0; | 329 return access(path.value().c_str(), F_OK) == 0; |
| 355 } | 330 } |
| 356 | 331 |
| 357 bool PathIsWritable(const FilePath& path) { | 332 bool PathIsWritable(const FilePath& path) { |
| 358 base::ThreadRestrictions::AssertIOAllowed(); | 333 base::ThreadRestrictions::AssertIOAllowed(); |
| 359 return access(path.value().c_str(), W_OK) == 0; | 334 return access(path.value().c_str(), W_OK) == 0; |
| 360 } | 335 } |
| 361 | 336 |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 814 return FilePath(home_dir); | 789 return FilePath(home_dir); |
| 815 #endif | 790 #endif |
| 816 | 791 |
| 817 FilePath rv; | 792 FilePath rv; |
| 818 if (file_util::GetTempDir(&rv)) | 793 if (file_util::GetTempDir(&rv)) |
| 819 return rv; | 794 return rv; |
| 820 | 795 |
| 821 // Last resort. | 796 // Last resort. |
| 822 return FilePath("/tmp"); | 797 return FilePath("/tmp"); |
| 823 } | 798 } |
| 824 | |
| 825 bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) { | |
| 826 base::ThreadRestrictions::AssertIOAllowed(); | |
| 827 int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY)); | |
| 828 if (infile < 0) | |
| 829 return false; | |
| 830 | |
| 831 int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666)); | |
| 832 if (outfile < 0) { | |
| 833 ignore_result(HANDLE_EINTR(close(infile))); | |
| 834 return false; | |
| 835 } | |
| 836 | |
| 837 const size_t kBufferSize = 32768; | |
| 838 std::vector<char> buffer(kBufferSize); | |
| 839 bool result = true; | |
| 840 | |
| 841 while (result) { | |
| 842 ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size())); | |
| 843 if (bytes_read < 0) { | |
| 844 result = false; | |
| 845 break; | |
| 846 } | |
| 847 if (bytes_read == 0) | |
| 848 break; | |
| 849 // Allow for partial writes | |
| 850 ssize_t bytes_written_per_read = 0; | |
| 851 do { | |
| 852 ssize_t bytes_written_partial = HANDLE_EINTR(write( | |
| 853 outfile, | |
| 854 &buffer[bytes_written_per_read], | |
| 855 bytes_read - bytes_written_per_read)); | |
| 856 if (bytes_written_partial < 0) { | |
| 857 result = false; | |
| 858 break; | |
| 859 } | |
| 860 bytes_written_per_read += bytes_written_partial; | |
| 861 } while (bytes_written_per_read < bytes_read); | |
| 862 } | |
| 863 | |
| 864 if (HANDLE_EINTR(close(infile)) < 0) | |
| 865 result = false; | |
| 866 if (HANDLE_EINTR(close(outfile)) < 0) | |
| 867 result = false; | |
| 868 | |
| 869 return result; | |
| 870 } | |
| 871 #endif // !defined(OS_MACOSX) | 799 #endif // !defined(OS_MACOSX) |
| 872 | 800 |
| 873 bool VerifyPathControlledByUser(const FilePath& base, | 801 bool VerifyPathControlledByUser(const FilePath& base, |
| 874 const FilePath& path, | 802 const FilePath& path, |
| 875 uid_t owner_uid, | 803 uid_t owner_uid, |
| 876 const std::set<gid_t>& group_gids) { | 804 const std::set<gid_t>& group_gids) { |
| 877 if (base != path && !base.IsParent(path)) { | 805 if (base != path && !base.IsParent(path)) { |
| 878 DLOG(ERROR) << "|base| must be a subdirectory of |path|. base = \"" | 806 DLOG(ERROR) << "|base| must be a subdirectory of |path|. base = \"" |
| 879 << base.value() << "\", path = \"" << path.value() << "\""; | 807 << base.value() << "\", path = \"" << path.value() << "\""; |
| 880 return false; | 808 return false; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 939 kFileSystemRoot, path, kRootUid, allowed_group_ids); | 867 kFileSystemRoot, path, kRootUid, allowed_group_ids); |
| 940 } | 868 } |
| 941 #endif // defined(OS_MACOSX) && !defined(OS_IOS) | 869 #endif // defined(OS_MACOSX) && !defined(OS_IOS) |
| 942 | 870 |
| 943 int GetMaximumPathComponentLength(const FilePath& path) { | 871 int GetMaximumPathComponentLength(const FilePath& path) { |
| 944 base::ThreadRestrictions::AssertIOAllowed(); | 872 base::ThreadRestrictions::AssertIOAllowed(); |
| 945 return pathconf(path.value().c_str(), _PC_NAME_MAX); | 873 return pathconf(path.value().c_str(), _PC_NAME_MAX); |
| 946 } | 874 } |
| 947 | 875 |
| 948 } // namespace file_util | 876 } // namespace file_util |
| 877 |
| 878 namespace base { |
| 879 namespace internal { |
| 880 |
| 881 bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) { |
| 882 ThreadRestrictions::AssertIOAllowed(); |
| 883 // Windows compatibility: if to_path exists, from_path and to_path |
| 884 // must be the same type, either both files, or both directories. |
| 885 stat_wrapper_t to_file_info; |
| 886 if (CallStat(to_path.value().c_str(), &to_file_info) == 0) { |
| 887 stat_wrapper_t from_file_info; |
| 888 if (CallStat(from_path.value().c_str(), &from_file_info) == 0) { |
| 889 if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode)) |
| 890 return false; |
| 891 } else { |
| 892 return false; |
| 893 } |
| 894 } |
| 895 |
| 896 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) |
| 897 return true; |
| 898 |
| 899 if (!CopyDirectory(from_path, to_path, true)) |
| 900 return false; |
| 901 |
| 902 Delete(from_path, true); |
| 903 return true; |
| 904 } |
| 905 |
| 906 #if !defined(OS_MACOSX) |
| 907 // Mac has its own implementation, this is for all other Posix systems. |
| 908 bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) { |
| 909 ThreadRestrictions::AssertIOAllowed(); |
| 910 int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY)); |
| 911 if (infile < 0) |
| 912 return false; |
| 913 |
| 914 int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666)); |
| 915 if (outfile < 0) { |
| 916 ignore_result(HANDLE_EINTR(close(infile))); |
| 917 return false; |
| 918 } |
| 919 |
| 920 const size_t kBufferSize = 32768; |
| 921 std::vector<char> buffer(kBufferSize); |
| 922 bool result = true; |
| 923 |
| 924 while (result) { |
| 925 ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size())); |
| 926 if (bytes_read < 0) { |
| 927 result = false; |
| 928 break; |
| 929 } |
| 930 if (bytes_read == 0) |
| 931 break; |
| 932 // Allow for partial writes |
| 933 ssize_t bytes_written_per_read = 0; |
| 934 do { |
| 935 ssize_t bytes_written_partial = HANDLE_EINTR(write( |
| 936 outfile, |
| 937 &buffer[bytes_written_per_read], |
| 938 bytes_read - bytes_written_per_read)); |
| 939 if (bytes_written_partial < 0) { |
| 940 result = false; |
| 941 break; |
| 942 } |
| 943 bytes_written_per_read += bytes_written_partial; |
| 944 } while (bytes_written_per_read < bytes_read); |
| 945 } |
| 946 |
| 947 if (HANDLE_EINTR(close(infile)) < 0) |
| 948 result = false; |
| 949 if (HANDLE_EINTR(close(outfile)) < 0) |
| 950 result = false; |
| 951 |
| 952 return result; |
| 953 } |
| 954 #endif // !defined(OS_MACOSX) |
| 955 |
| 956 } // namespace internal |
| 957 } // namespace base |
| OLD | NEW |