1 // Copyright (c) 2011 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 7 #include <dirent.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <fnmatch.h> 11 #include <libgen.h> 12 #include <limits.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <sys/errno.h> 17 #include <sys/mman.h> 18 #include <sys/param.h> 19 #include <sys/stat.h> 20 #include <sys/time.h> 21 #include <sys/types.h> 22 #include <time.h> 23 #include <unistd.h> 24 25 #if defined(OS_MACOSX) 26 #include <AvailabilityMacros.h> 27 #elif !defined(ANDROID) 28 #include <glib.h> 29 #endif 30 31 #include <fstream> 32 33 #include "base/basictypes.h" 34 #include "base/eintr_wrapper.h" 35 #include "base/file_path.h" 36 #include "base/logging.h" 37 #include "base/memory/scoped_ptr.h" 38 #include "base/memory/singleton.h" 39 #include "base/string_util.h" 40 #include "base/sys_string_conversions.h" 41 #include "base/threading/thread_restrictions.h" 42 #include "base/time.h" 43 #include "base/utf_string_conversions.h" 44 45 namespace file_util { 46 47 namespace { 48 49 // Helper for NormalizeFilePath(), defined below. 50 bool RealPath(const FilePath& path, FilePath* real_path) { 51 base::ThreadRestrictions::AssertIOAllowed(); // For realpath(). 52 FilePath::CharType buf[PATH_MAX]; 53 if (!realpath(path.value().c_str(), buf)) 54 return false; 55 56 *real_path = FilePath(buf); 57 return true; 58 } 59 60 } // namespace 61 62 #if defined(OS_OPENBSD) || defined(OS_FREEBSD) || \ 63 (defined(OS_MACOSX) && \ 64 MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) 65 typedef struct stat stat_wrapper_t; 66 static int CallStat(const char *path, stat_wrapper_t *sb) { 67 base::ThreadRestrictions::AssertIOAllowed(); 68 return stat(path, sb); 69 } 70 #else 71 typedef struct stat64 stat_wrapper_t; 72 static int CallStat(const char *path, stat_wrapper_t *sb) { 73 base::ThreadRestrictions::AssertIOAllowed(); 74 return stat64(path, sb); 75 } 76 #endif 77 78 79 #if defined(GOOGLE_CHROME_BUILD) 80 static const char* kTempFileName = ".com.google.chrome.XXXXXX"; 81 #else 82 static const char* kTempFileName = ".org.chromium.XXXXXX"; 83 #endif 84 85 bool AbsolutePath(FilePath* path) { 86 base::ThreadRestrictions::AssertIOAllowed(); // For realpath(). 87 char full_path[PATH_MAX]; 88 if (realpath(path->value().c_str(), full_path) == NULL) 89 return false; 90 *path = FilePath(full_path); 91 return true; 92 } 93 94 int CountFilesCreatedAfter(const FilePath& path, 95 const base::Time& comparison_time) { 96 base::ThreadRestrictions::AssertIOAllowed(); 97 int file_count = 0; 98 99 DIR* dir = opendir(path.value().c_str()); 100 if (dir) { 101 #if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_FREEBSD) && \ 102 !defined(OS_OPENBSD) && !defined(OS_SOLARIS) 103 #error Port warning: depending on the definition of struct dirent, \ 104 additional space for pathname may be needed 105 #endif 106 struct dirent ent_buf; 107 struct dirent* ent; 108 while (readdir_r(dir, &ent_buf, &ent) == 0 && ent) { 109 if ((strcmp(ent->d_name, ".") == 0) || 110 (strcmp(ent->d_name, "..") == 0)) 111 continue; 112 113 stat_wrapper_t st; 114 int test = CallStat(path.Append(ent->d_name).value().c_str(), &st); 115 if (test != 0) { 116 PLOG(ERROR) << "stat64 failed"; 117 continue; 118 } 119 // Here, we use Time::TimeT(), which discards microseconds. This 120 // means that files which are newer than |comparison_time| may 121 // be considered older. If we don't discard microseconds, it 122 // introduces another issue. Suppose the following case: 123 // 124 // 1. Get |comparison_time| by Time::Now() and the value is 10.1 (secs). 125 // 2. Create a file and the current time is 10.3 (secs). 126 // 127 // As POSIX doesn't have microsecond precision for |st_ctime|, 128 // the creation time of the file created in the step 2 is 10 and 129 // the file is considered older than |comparison_time|. After 130 // all, we may have to accept either of the two issues: 1. files 131 // which are older than |comparison_time| are considered newer 132 // (current implementation) 2. files newer than 133 // |comparison_time| are considered older. 134 if (static_cast<time_t>(st.st_ctime) >= comparison_time.ToTimeT()) 135 ++file_count; 136 } 137 closedir(dir); 138 } 139 return file_count; 140 } 141 142 // TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*" 143 // which works both with and without the recursive flag. I'm not sure we need 144 // that functionality. If not, remove from file_util_win.cc, otherwise add it 145 // here. 146 bool Delete(const FilePath& path, bool recursive) { 147 base::ThreadRestrictions::AssertIOAllowed(); 148 const char* path_str = path.value().c_str(); 149 stat_wrapper_t file_info; 150 int test = CallStat(path_str, &file_info); 151 if (test != 0) { 152 // The Windows version defines this condition as success. 153 bool ret = (errno == ENOENT || errno == ENOTDIR); 154 return ret; 155 } 156 if (!S_ISDIR(file_info.st_mode)) 157 return (unlink(path_str) == 0); 158 if (!recursive) 159 return (rmdir(path_str) == 0); 160 161 bool success = true; 162 std::stack<std::string> directories; 163 directories.push(path.value()); 164 FileEnumerator traversal(path, true, static_cast<FileEnumerator::FILE_TYPE>( 165 FileEnumerator::FILES | FileEnumerator::DIRECTORIES | 166 FileEnumerator::SHOW_SYM_LINKS)); 167 for (FilePath current = traversal.Next(); success && !current.empty(); 168 current = traversal.Next()) { 169 FileEnumerator::FindInfo info; 170 traversal.GetFindInfo(&info); 171 172 if (S_ISDIR(info.stat.st_mode)) 173 directories.push(current.value()); 174 else 175 success = (unlink(current.value().c_str()) == 0); 176 } 177 178 while (success && !directories.empty()) { 179 FilePath dir = FilePath(directories.top()); 180 directories.pop(); 181 success = (rmdir(dir.value().c_str()) == 0); 182 } 183 return success; 184 } 185 186 bool Move(const FilePath& from_path, const FilePath& to_path) { 187 base::ThreadRestrictions::AssertIOAllowed(); 188 // Windows compatibility: if to_path exists, from_path and to_path 189 // must be the same type, either both files, or both directories. 190 stat_wrapper_t to_file_info; 191 if (CallStat(to_path.value().c_str(), &to_file_info) == 0) { 192 stat_wrapper_t from_file_info; 193 if (CallStat(from_path.value().c_str(), &from_file_info) == 0) { 194 if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode)) 195 return false; 196 } else { 197 return false; 198 } 199 } 200 201 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) 202 return true; 203 204 if (!CopyDirectory(from_path, to_path, true)) 205 return false; 206 207 Delete(from_path, true); 208 return true; 209 } 210 211 bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) { 212 base::ThreadRestrictions::AssertIOAllowed(); 213 return (rename(from_path.value().c_str(), to_path.value().c_str()) == 0); 214 } 215 216 bool CopyDirectory(const FilePath& from_path, 217 const FilePath& to_path, 218 bool recursive) { 219 base::ThreadRestrictions::AssertIOAllowed(); 220 // Some old callers of CopyDirectory want it to support wildcards. 221 // After some discussion, we decided to fix those callers. 222 // Break loudly here if anyone tries to do this. 223 // TODO(evanm): remove this once we're sure it's ok. 224 DCHECK(to_path.value().find('*') == std::string::npos); 225 DCHECK(from_path.value().find('*') == std::string::npos); 226 227 char top_dir[PATH_MAX]; 228 if (base::strlcpy(top_dir, from_path.value().c_str(), 229 arraysize(top_dir)) >= arraysize(top_dir)) { 230 return false; 231 } 232 233 // This function does not properly handle destinations within the source 234 FilePath real_to_path = to_path; 235 if (PathExists(real_to_path)) { 236 if (!AbsolutePath(&real_to_path)) 237 return false; 238 } else { 239 real_to_path = real_to_path.DirName(); 240 if (!AbsolutePath(&real_to_path)) 241 return false; 242 } 243 FilePath real_from_path = from_path; 244 if (!AbsolutePath(&real_from_path)) 245 return false; 246 if (real_to_path.value().size() >= real_from_path.value().size() && 247 real_to_path.value().compare(0, real_from_path.value().size(), 248 real_from_path.value()) == 0) 249 return false; 250 251 bool success = true; 252 FileEnumerator::FILE_TYPE traverse_type = 253 static_cast<FileEnumerator::FILE_TYPE>(FileEnumerator::FILES | 254 FileEnumerator::SHOW_SYM_LINKS); 255 if (recursive) 256 traverse_type = static_cast<FileEnumerator::FILE_TYPE>( 257 traverse_type | FileEnumerator::DIRECTORIES); 258 FileEnumerator traversal(from_path, recursive, traverse_type); 259 260 // We have to mimic windows behavior here. |to_path| may not exist yet, 261 // start the loop with |to_path|. 262 FileEnumerator::FindInfo info; 263 FilePath current = from_path; 264 if (stat(from_path.value().c_str(), &info.stat) < 0) { 265 LOG(ERROR) << "CopyDirectory() couldn't stat source directory: " << 266 from_path.value() << " errno = " << errno; 267 success = false; 268 } 269 struct stat to_path_stat; 270 FilePath from_path_base = from_path; 271 if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 && 272 S_ISDIR(to_path_stat.st_mode)) { 273 // If the destination already exists and is a directory, then the 274 // top level of source needs to be copied. 275 from_path_base = from_path.DirName(); 276 } 277 278 // The Windows version of this function assumes that non-recursive calls 279 // will always have a directory for from_path. 280 DCHECK(recursive || S_ISDIR(info.stat.st_mode)); 281 282 while (success && !current.empty()) { 283 // current is the source path, including from_path, so paste 284 // the suffix after from_path onto to_path to create the target_path. 285 std::string suffix(¤t.value().c_str()[from_path_base.value().size()]); 286 // Strip the leading '/' (if any). 287 if (!suffix.empty()) { 288 DCHECK_EQ('/', suffix[0]); 289 suffix.erase(0, 1); 290 } 291 const FilePath target_path = to_path.Append(suffix); 292 293 if (S_ISDIR(info.stat.st_mode)) { 294 if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 && 295 errno != EEXIST) { 296 LOG(ERROR) << "CopyDirectory() couldn't create directory: " << 297 target_path.value() << " errno = " << errno; 298 success = false; 299 } 300 } else if (S_ISREG(info.stat.st_mode)) { 301 if (!CopyFile(current, target_path)) { 302 LOG(ERROR) << "CopyDirectory() couldn't create file: " << 303 target_path.value(); 304 success = false; 305 } 306 } else { 307 LOG(WARNING) << "CopyDirectory() skipping non-regular file: " << 308 current.value(); 309 } 310 311 current = traversal.Next(); 312 traversal.GetFindInfo(&info); 313 } 314 315 return success; 316 } 317 318 bool PathExists(const FilePath& path) { 319 base::ThreadRestrictions::AssertIOAllowed(); 320 return access(path.value().c_str(), F_OK) == 0; 321 } 322 323 bool PathIsWritable(const FilePath& path) { 324 base::ThreadRestrictions::AssertIOAllowed(); 325 return access(path.value().c_str(), W_OK) == 0; 326 } 327 328 bool DirectoryExists(const FilePath& path) { 329 base::ThreadRestrictions::AssertIOAllowed(); 330 stat_wrapper_t file_info; 331 if (CallStat(path.value().c_str(), &file_info) == 0) 332 return S_ISDIR(file_info.st_mode); 333 return false; 334 } 335 336 // TODO(erikkay): implement 337 #if 0 338 bool GetFileCreationLocalTimeFromHandle(int fd, 339 LPSYSTEMTIME creation_time) { 340 if (!file_handle) 341 return false; 342 343 FILETIME utc_filetime; 344 if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL)) 345 return false; 346 347 FILETIME local_filetime; 348 if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime)) 349 return false; 350 351 return !!FileTimeToSystemTime(&local_filetime, creation_time); 352 } 353 354 bool GetFileCreationLocalTime(const std::string& filename, 355 LPSYSTEMTIME creation_time) { 356 ScopedHandle file_handle( 357 CreateFile(filename.c_str(), GENERIC_READ, 358 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 359 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); 360 return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time); 361 } 362 #endif 363 364 bool ReadFromFD(int fd, char* buffer, size_t bytes) { 365 size_t total_read = 0; 366 while (total_read < bytes) { 367 ssize_t bytes_read = 368 HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read)); 369 if (bytes_read <= 0) 370 break; 371 total_read += bytes_read; 372 } 373 return total_read == bytes; 374 } 375 376 bool CreateSymbolicLink(const FilePath& target_path, 377 const FilePath& symlink_path) { 378 DCHECK(!symlink_path.empty()); 379 DCHECK(!target_path.empty()); 380 return ::symlink(target_path.value().c_str(), 381 symlink_path.value().c_str()) != -1; 382 } 383 384 bool ReadSymbolicLink(const FilePath& symlink_path, 385 FilePath* target_path) { 386 DCHECK(!symlink_path.empty()); 387 DCHECK(target_path); 388 char buf[PATH_MAX]; 389 ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf)); 390 391 if (count <= 0) { 392 target_path->clear(); 393 return false; 394 } 395 396 *target_path = FilePath(FilePath::StringType(buf, count)); 397 return true; 398 } 399 400 // Creates and opens a temporary file in |directory|, returning the 401 // file descriptor. |path| is set to the temporary file path. 402 // This function does NOT unlink() the file. 403 int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) { 404 base::ThreadRestrictions::AssertIOAllowed(); // For call to mkstemp(). 405 *path = directory.Append(kTempFileName); 406 const std::string& tmpdir_string = path->value(); 407 // this should be OK since mkstemp just replaces characters in place 408 char* buffer = const_cast<char*>(tmpdir_string.c_str()); 409 410 return HANDLE_EINTR(mkstemp(buffer)); 411 } 412 413 bool CreateTemporaryFile(FilePath* path) { 414 base::ThreadRestrictions::AssertIOAllowed(); // For call to close(). 415 FilePath directory; 416 if (!GetTempDir(&directory)) 417 return false; 418 int fd = CreateAndOpenFdForTemporaryFile(directory, path); 419 if (fd < 0) 420 return false; 421 ignore_result(HANDLE_EINTR(close(fd))); 422 return true; 423 } 424 425 FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) { 426 FilePath directory; 427 if (!GetShmemTempDir(&directory)) 428 return NULL; 429 430 return CreateAndOpenTemporaryFileInDir(directory, path); 431 } 432 433 FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { 434 int fd = CreateAndOpenFdForTemporaryFile(dir, path); 435 if (fd < 0) 436 return NULL; 437 438 FILE* file = fdopen(fd, "a+"); 439 if (!file) 440 ignore_result(HANDLE_EINTR(close(fd))); 441 return file; 442 } 443 444 bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) { 445 base::ThreadRestrictions::AssertIOAllowed(); // For call to close(). 446 int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file); 447 return ((fd >= 0) && !HANDLE_EINTR(close(fd))); 448 } 449 450 static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir, 451 const FilePath::StringType& name_tmpl, 452 FilePath* new_dir) { 453 base::ThreadRestrictions::AssertIOAllowed(); // For call to mkdtemp(). 454 CHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos) 455 << "Directory name template must contain \"XXXXXX\"."; 456 457 FilePath sub_dir = base_dir.Append(name_tmpl); 458 std::string sub_dir_string = sub_dir.value(); 459 460 // this should be OK since mkdtemp just replaces characters in place 461 char* buffer = const_cast<char*>(sub_dir_string.c_str()); 462 char* dtemp = mkdtemp(buffer); 463 if (!dtemp) { 464 DPLOG(ERROR) << "mkdtemp"; 465 return false; 466 } 467 *new_dir = FilePath(dtemp); 468 return true; 469 } 470 471 bool CreateTemporaryDirInDir(const FilePath& base_dir, 472 const FilePath::StringType& prefix, 473 FilePath* new_dir) { 474 FilePath::StringType mkdtemp_template = prefix; 475 mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX")); 476 return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir); 477 } 478 479 bool CreateNewTempDirectory(const FilePath::StringType& prefix, 480 FilePath* new_temp_path) { 481 FilePath tmpdir; 482 if (!GetTempDir(&tmpdir)) 483 return false; 484 485 return CreateTemporaryDirInDirImpl(tmpdir, kTempFileName, new_temp_path); 486 } 487 488 bool CreateDirectory(const FilePath& full_path) { 489 base::ThreadRestrictions::AssertIOAllowed(); // For call to mkdir(). 490 std::vector<FilePath> subpaths; 491 492 // Collect a list of all parent directories. 493 FilePath last_path = full_path; 494 subpaths.push_back(full_path); 495 for (FilePath path = full_path.DirName(); 496 path.value() != last_path.value(); path = path.DirName()) { 497 subpaths.push_back(path); 498 last_path = path; 499 } 500 501 // Iterate through the parents and create the missing ones. 502 for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin(); 503 i != subpaths.rend(); ++i) { 504 if (DirectoryExists(*i)) 505 continue; 506 if (mkdir(i->value().c_str(), 0700) == 0) 507 continue; 508 // Mkdir failed, but it might have failed with EEXIST, or some other error 509 // due to the the directory appearing out of thin air. This can occur if 510 // two processes are trying to create the same file system tree at the same 511 // time. Check to see if it exists and make sure it is a directory. 512 if (!DirectoryExists(*i)) 513 return false; 514 } 515 return true; 516 } 517 518 bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) { 519 stat_wrapper_t file_info; 520 if (CallStat(file_path.value().c_str(), &file_info) != 0) 521 return false; 522 results->is_directory = S_ISDIR(file_info.st_mode); 523 results->size = file_info.st_size; 524 results->last_modified = base::Time::FromTimeT(file_info.st_mtime); 525 results->last_accessed = base::Time::FromTimeT(file_info.st_atime); 526 results->creation_time = base::Time::FromTimeT(file_info.st_ctime); 527 return true; 528 } 529 530 bool GetInode(const FilePath& path, ino_t* inode) { 531 base::ThreadRestrictions::AssertIOAllowed(); // For call to stat(). 532 struct stat buffer; 533 int result = stat(path.value().c_str(), &buffer); 534 if (result < 0) 535 return false; 536 537 *inode = buffer.st_ino; 538 return true; 539 } 540 541 FILE* OpenFile(const std::string& filename, const char* mode) { 542 return OpenFile(FilePath(filename), mode); 543 } 544 545 FILE* OpenFile(const FilePath& filename, const char* mode) { 546 base::ThreadRestrictions::AssertIOAllowed(); 547 FILE* result = NULL; 548 do { 549 result = fopen(filename.value().c_str(), mode); 550 } while (!result && errno == EINTR); 551 return result; 552 } 553 554 int ReadFile(const FilePath& filename, char* data, int size) { 555 base::ThreadRestrictions::AssertIOAllowed(); 556 int fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY)); 557 if (fd < 0) 558 return -1; 559 560 ssize_t bytes_read = HANDLE_EINTR(read(fd, data, size)); 561 if (int ret = HANDLE_EINTR(close(fd)) < 0) 562 return ret; 563 return bytes_read; 564 } 565 566 int WriteFile(const FilePath& filename, const char* data, int size) { 567 base::ThreadRestrictions::AssertIOAllowed(); 568 int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666)); 569 if (fd < 0) 570 return -1; 571 572 int bytes_written = WriteFileDescriptor(fd, data, size); 573 if (int ret = HANDLE_EINTR(close(fd)) < 0) 574 return ret; 575 return bytes_written; 576 } 577 578 int WriteFileDescriptor(const int fd, const char* data, int size) { 579 // Allow for partial writes. 580 ssize_t bytes_written_total = 0; 581 for (ssize_t bytes_written_partial = 0; bytes_written_total < size; 582 bytes_written_total += bytes_written_partial) { 583 bytes_written_partial = 584 HANDLE_EINTR(write(fd, data + bytes_written_total, 585 size - bytes_written_total)); 586 if (bytes_written_partial < 0) 587 return -1; 588 } 589 590 return bytes_written_total; 591 } 592 593 // Gets the current working directory for the process. 594 bool GetCurrentDirectory(FilePath* dir) { 595 // getcwd can return ENOENT, which implies it checks against the disk. 596 base::ThreadRestrictions::AssertIOAllowed(); 597 598 char system_buffer[PATH_MAX] = ""; 599 if (!getcwd(system_buffer, sizeof(system_buffer))) { 600 NOTREACHED(); 601 return false; 602 } 603 *dir = FilePath(system_buffer); 604 return true; 605 } 606 607 // Sets the current working directory for the process. 608 bool SetCurrentDirectory(const FilePath& path) { 609 base::ThreadRestrictions::AssertIOAllowed(); 610 int ret = chdir(path.value().c_str()); 611 return !ret; 612 } 613 614 /////////////////////////////////////////////// 615 // FileEnumerator 616 617 FileEnumerator::FileEnumerator(const FilePath& root_path, 618 bool recursive, 619 FileEnumerator::FILE_TYPE file_type) 620 : current_directory_entry_(0), 621 root_path_(root_path), 622 recursive_(recursive), 623 file_type_(file_type) { 624 // INCLUDE_DOT_DOT must not be specified if recursive. 625 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); 626 pending_paths_.push(root_path); 627 } 628 629 FileEnumerator::FileEnumerator(const FilePath& root_path, 630 bool recursive, 631 FileEnumerator::FILE_TYPE file_type, 632 const FilePath::StringType& pattern) 633 : current_directory_entry_(0), 634 root_path_(root_path), 635 recursive_(recursive), 636 file_type_(file_type), 637 pattern_(root_path.Append(pattern).value()) { 638 // INCLUDE_DOT_DOT must not be specified if recursive. 639 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); 640 // The Windows version of this code appends the pattern to the root_path, 641 // potentially only matching against items in the top-most directory. 642 // Do the same here. 643 if (pattern.empty()) 644 pattern_ = FilePath::StringType(); 645 pending_paths_.push(root_path); 646 } 647 648 FileEnumerator::~FileEnumerator() { 649 } 650 651 FilePath FileEnumerator::Next() { 652 ++current_directory_entry_; 653 654 // While we've exhausted the entries in the current directory, do the next 655 while (current_directory_entry_ >= directory_entries_.size()) { 656 if (pending_paths_.empty()) 657 return FilePath(); 658 659 root_path_ = pending_paths_.top(); 660 root_path_ = root_path_.StripTrailingSeparators(); 661 pending_paths_.pop(); 662 663 std::vector<DirectoryEntryInfo> entries; 664 if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS)) 665 continue; 666 667 directory_entries_.clear(); 668 current_directory_entry_ = 0; 669 for (std::vector<DirectoryEntryInfo>::const_iterator 670 i = entries.begin(); i != entries.end(); ++i) { 671 FilePath full_path = root_path_.Append(i->filename); 672 if (ShouldSkip(full_path)) 673 continue; 674 675 if (pattern_.size() && 676 fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE)) 677 continue; 678 679 if (recursive_ && S_ISDIR(i->stat.st_mode)) 680 pending_paths_.push(full_path); 681 682 if ((S_ISDIR(i->stat.st_mode) && (file_type_ & DIRECTORIES)) || 683 (!S_ISDIR(i->stat.st_mode) && (file_type_ & FILES))) 684 directory_entries_.push_back(*i); 685 } 686 } 687 688 return root_path_.Append(directory_entries_[current_directory_entry_ 689 ].filename); 690 } 691 692 void FileEnumerator::GetFindInfo(FindInfo* info) { 693 DCHECK(info); 694 695 if (current_directory_entry_ >= directory_entries_.size()) 696 return; 697 698 DirectoryEntryInfo* cur_entry = &directory_entries_[current_directory_entry_]; 699 memcpy(&(info->stat), &(cur_entry->stat), sizeof(info->stat)); 700 info->filename.assign(cur_entry->filename.value()); 701 } 702 703 bool FileEnumerator::IsDirectory(const FindInfo& info) { 704 return S_ISDIR(info.stat.st_mode); 705 } 706 707 // static 708 FilePath FileEnumerator::GetFilename(const FindInfo& find_info) { 709 return FilePath(find_info.filename); 710 } 711 712 bool FileEnumerator::ReadDirectory(std::vector<DirectoryEntryInfo>* entries, 713 const FilePath& source, bool show_links) { 714 base::ThreadRestrictions::AssertIOAllowed(); 715 DIR* dir = opendir(source.value().c_str()); 716 if (!dir) 717 return false; 718 719 #if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_FREEBSD) && \ 720 !defined(OS_OPENBSD) && !defined(OS_SOLARIS) 721 #error Port warning: depending on the definition of struct dirent, \ 722 additional space for pathname may be needed 723 #endif 724 725 struct dirent dent_buf; 726 struct dirent* dent; 727 while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) { 728 DirectoryEntryInfo info; 729 info.filename = FilePath(dent->d_name); 730 731 FilePath full_name = source.Append(dent->d_name); 732 int ret; 733 if (show_links) 734 ret = lstat(full_name.value().c_str(), &info.stat); 735 else 736 ret = stat(full_name.value().c_str(), &info.stat); 737 if (ret < 0) { 738 // Print the stat() error message unless it was ENOENT and we're 739 // following symlinks. 740 if (!(errno == ENOENT && !show_links)) { 741 PLOG(ERROR) << "Couldn't stat " 742 << source.Append(dent->d_name).value(); 743 } 744 memset(&info.stat, 0, sizeof(info.stat)); 745 } 746 entries->push_back(info); 747 } 748 749 closedir(dir); 750 return true; 751 } 752 753 /////////////////////////////////////////////// 754 // MemoryMappedFile 755 756 MemoryMappedFile::MemoryMappedFile() 757 : file_(base::kInvalidPlatformFileValue), 758 data_(NULL), 759 length_(0) { 760 } 761 762 bool MemoryMappedFile::MapFileToMemoryInternal() { 763 base::ThreadRestrictions::AssertIOAllowed(); 764 765 struct stat file_stat; 766 if (fstat(file_, &file_stat) == base::kInvalidPlatformFileValue) { 767 LOG(ERROR) << "Couldn't fstat " << file_ << ", errno " << errno; 768 return false; 769 } 770 length_ = file_stat.st_size; 771 772 data_ = static_cast<uint8*>( 773 mmap(NULL, length_, PROT_READ, MAP_SHARED, file_, 0)); 774 if (data_ == MAP_FAILED) 775 LOG(ERROR) << "Couldn't mmap " << file_ << ", errno " << errno; 776 777 return data_ != MAP_FAILED; 778 } 779 780 void MemoryMappedFile::CloseHandles() { 781 base::ThreadRestrictions::AssertIOAllowed(); 782 783 if (data_ != NULL) 784 munmap(data_, length_); 785 if (file_ != base::kInvalidPlatformFileValue) 786 ignore_result(HANDLE_EINTR(close(file_))); 787 788 data_ = NULL; 789 length_ = 0; 790 file_ = base::kInvalidPlatformFileValue; 791 } 792 793 bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info, 794 const base::Time& cutoff_time) { 795 return static_cast<time_t>(find_info.stat.st_mtime) >= cutoff_time.ToTimeT(); 796 } 797 798 bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) { 799 FilePath real_path_result; 800 if (!RealPath(path, &real_path_result)) 801 return false; 802 803 // To be consistant with windows, fail if |real_path_result| is a 804 // directory. 805 stat_wrapper_t file_info; 806 if (CallStat(real_path_result.value().c_str(), &file_info) != 0 || 807 S_ISDIR(file_info.st_mode)) 808 return false; 809 810 *normalized_path = real_path_result; 811 return true; 812 } 813 814 #if !defined(OS_MACOSX) 815 bool GetTempDir(FilePath* path) { 816 const char* tmp = getenv("TMPDIR"); 817 if (tmp) 818 *path = FilePath(tmp); 819 else 820 *path = FilePath("/tmp"); 821 return true; 822 } 823 824 bool GetShmemTempDir(FilePath* path) { 825 *path = FilePath("/dev/shm"); 826 return true; 827 } 828 829 FilePath GetHomeDir() { 830 #ifndef ANDROID 831 const char* home_dir = getenv("HOME"); 832 if (home_dir && home_dir[0]) 833 return FilePath(home_dir); 834 835 // g_get_home_dir calls getpwent, which can fall through to LDAP calls. 836 base::ThreadRestrictions::AssertIOAllowed(); 837 838 home_dir = g_get_home_dir(); 839 if (home_dir && home_dir[0]) 840 return FilePath(home_dir); 841 842 FilePath rv; 843 if (file_util::GetTempDir(&rv)) 844 return rv; 845 #endif 846 // Last resort. 847 return FilePath("/tmp"); 848 } 849 850 bool CopyFile(const FilePath& from_path, const FilePath& to_path) { 851 base::ThreadRestrictions::AssertIOAllowed(); 852 int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY)); 853 if (infile < 0) 854 return false; 855 856 int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666)); 857 if (outfile < 0) { 858 ignore_result(HANDLE_EINTR(close(infile))); 859 return false; 860 } 861 862 const size_t kBufferSize = 32768; 863 std::vector<char> buffer(kBufferSize); 864 bool result = true; 865 866 while (result) { 867 ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size())); 868 if (bytes_read < 0) { 869 result = false; 870 break; 871 } 872 if (bytes_read == 0) 873 break; 874 // Allow for partial writes 875 ssize_t bytes_written_per_read = 0; 876 do { 877 ssize_t bytes_written_partial = HANDLE_EINTR(write( 878 outfile, 879 &buffer[bytes_written_per_read], 880 bytes_read - bytes_written_per_read)); 881 if (bytes_written_partial < 0) { 882 result = false; 883 break; 884 } 885 bytes_written_per_read += bytes_written_partial; 886 } while (bytes_written_per_read < bytes_read); 887 } 888 889 if (HANDLE_EINTR(close(infile)) < 0) 890 result = false; 891 if (HANDLE_EINTR(close(outfile)) < 0) 892 result = false; 893 894 return result; 895 } 896 #endif // defined(OS_MACOSX) 897 898 } // namespace file_util 899