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 |