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 3 // found in the LICENSE file. 4 5 #include "base/files/file_util.h" 6 7 #include <dirent.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <libgen.h> 11 #include <limits.h> 12 #include <stddef.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 #include "base/environment.h" 26 #include "base/files/file_enumerator.h" 27 #include "base/files/file_path.h" 28 #include "base/files/scoped_file.h" 29 #include "base/logging.h" 30 #include "base/macros.h" 31 #include "base/memory/singleton.h" 32 #include "base/posix/eintr_wrapper.h" 33 #include "base/stl_util.h" 34 #include "base/strings/string_split.h" 35 #include "base/strings/string_util.h" 36 #include "base/strings/stringprintf.h" 37 #include "base/strings/sys_string_conversions.h" 38 #include "base/strings/utf_string_conversions.h" 39 #include "base/sys_info.h" 40 #include "base/threading/thread_restrictions.h" 41 #include "base/time/time.h" 42 #include "build/build_config.h" 43 44 #if defined(OS_MACOSX) 45 #include <AvailabilityMacros.h> 46 #include "base/mac/foundation_util.h" 47 #endif 48 49 #if defined(OS_ANDROID) 50 #include "base/android/content_uri_utils.h" 51 #include "base/os_compat_android.h" 52 #include "base/path_service.h" 53 #endif 54 55 #if !defined(OS_IOS) 56 #include <grp.h> 57 #endif 58 59 namespace base { 60 61 namespace { 62 63 #if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) 64 static int CallStat(const char *path, stat_wrapper_t *sb) { 65 ThreadRestrictions::AssertIOAllowed(); 66 return stat(path, sb); 67 } 68 static int CallLstat(const char *path, stat_wrapper_t *sb) { 69 ThreadRestrictions::AssertIOAllowed(); 70 return lstat(path, sb); 71 } 72 #else // defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL) 73 static int CallStat(const char *path, stat_wrapper_t *sb) { 74 ThreadRestrictions::AssertIOAllowed(); 75 return stat64(path, sb); 76 } 77 static int CallLstat(const char *path, stat_wrapper_t *sb) { 78 ThreadRestrictions::AssertIOAllowed(); 79 return lstat64(path, sb); 80 } 81 #endif // !(defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)) 82 83 #if !defined(OS_NACL_NONSFI) 84 // Helper for NormalizeFilePath(), defined below. 85 bool RealPath(const FilePath& path, FilePath* real_path) { 86 ThreadRestrictions::AssertIOAllowed(); // For realpath(). 87 FilePath::CharType buf[PATH_MAX]; 88 if (!realpath(path.value().c_str(), buf)) 89 return false; 90 91 *real_path = FilePath(buf); 92 return true; 93 } 94 95 // Helper for VerifyPathControlledByUser. 96 bool VerifySpecificPathControlledByUser(const FilePath& path, 97 uid_t owner_uid, 98 const std::set<gid_t>& group_gids) { 99 stat_wrapper_t stat_info; 100 if (CallLstat(path.value().c_str(), &stat_info) != 0) { 101 DPLOG(ERROR) << "Failed to get information on path " 102 << path.value(); 103 return false; 104 } 105 106 if (S_ISLNK(stat_info.st_mode)) { 107 DLOG(ERROR) << "Path " << path.value() 108 << " is a symbolic link."; 109 return false; 110 } 111 112 if (stat_info.st_uid != owner_uid) { 113 DLOG(ERROR) << "Path " << path.value() 114 << " is owned by the wrong user."; 115 return false; 116 } 117 118 if ((stat_info.st_mode & S_IWGRP) && 119 !ContainsKey(group_gids, stat_info.st_gid)) { 120 DLOG(ERROR) << "Path " << path.value() 121 << " is writable by an unprivileged group."; 122 return false; 123 } 124 125 if (stat_info.st_mode & S_IWOTH) { 126 DLOG(ERROR) << "Path " << path.value() 127 << " is writable by any user."; 128 return false; 129 } 130 131 return true; 132 } 133 134 std::string TempFileName() { 135 #if defined(OS_MACOSX) 136 return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID()); 137 #endif 138 139 #if defined(GOOGLE_CHROME_BUILD) 140 return std::string(".com.google.Chrome.XXXXXX"); 141 #else 142 return std::string(".org.chromium.Chromium.XXXXXX"); 143 #endif 144 } 145 146 // Creates and opens a temporary file in |directory|, returning the 147 // file descriptor. |path| is set to the temporary file path. 148 // This function does NOT unlink() the file. 149 int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) { 150 ThreadRestrictions::AssertIOAllowed(); // For call to mkstemp(). 151 *path = directory.Append(base::TempFileName()); 152 const std::string& tmpdir_string = path->value(); 153 // this should be OK since mkstemp just replaces characters in place 154 char* buffer = const_cast<char*>(tmpdir_string.c_str()); 155 156 return HANDLE_EINTR(mkstemp(buffer)); 157 } 158 159 #if defined(OS_LINUX) 160 // Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC. 161 // This depends on the mount options used for /dev/shm, which vary among 162 // different Linux distributions and possibly local configuration. It also 163 // depends on details of kernel--ChromeOS uses the noexec option for /dev/shm 164 // but its kernel allows mprotect with PROT_EXEC anyway. 165 bool DetermineDevShmExecutable() { 166 bool result = false; 167 FilePath path; 168 169 ScopedFD fd(CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path)); 170 if (fd.is_valid()) { 171 DeleteFile(path, false); 172 long sysconf_result = sysconf(_SC_PAGESIZE); 173 CHECK_GE(sysconf_result, 0); 174 size_t pagesize = static_cast<size_t>(sysconf_result); 175 CHECK_GE(sizeof(pagesize), sizeof(sysconf_result)); 176 void* mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd.get(), 0); 177 if (mapping != MAP_FAILED) { 178 if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0) 179 result = true; 180 munmap(mapping, pagesize); 181 } 182 } 183 return result; 184 } 185 #endif // defined(OS_LINUX) 186 #endif // !defined(OS_NACL_NONSFI) 187 188 } // namespace 189 190 #if !defined(OS_NACL_NONSFI) 191 FilePath MakeAbsoluteFilePath(const FilePath& input) { 192 ThreadRestrictions::AssertIOAllowed(); 193 char full_path[PATH_MAX]; 194 if (realpath(input.value().c_str(), full_path) == NULL) 195 return FilePath(); 196 return FilePath(full_path); 197 } 198 199 // TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*" 200 // which works both with and without the recursive flag. I'm not sure we need 201 // that functionality. If not, remove from file_util_win.cc, otherwise add it 202 // here. 203 bool DeleteFile(const FilePath& path, bool recursive) { 204 ThreadRestrictions::AssertIOAllowed(); 205 const char* path_str = path.value().c_str(); 206 stat_wrapper_t file_info; 207 int test = CallLstat(path_str, &file_info); 208 if (test != 0) { 209 // The Windows version defines this condition as success. 210 bool ret = (errno == ENOENT || errno == ENOTDIR); 211 return ret; 212 } 213 if (!S_ISDIR(file_info.st_mode)) 214 return (unlink(path_str) == 0); 215 if (!recursive) 216 return (rmdir(path_str) == 0); 217 218 bool success = true; 219 std::stack<std::string> directories; 220 directories.push(path.value()); 221 FileEnumerator traversal(path, true, 222 FileEnumerator::FILES | FileEnumerator::DIRECTORIES | 223 FileEnumerator::SHOW_SYM_LINKS); 224 for (FilePath current = traversal.Next(); success && !current.empty(); 225 current = traversal.Next()) { 226 if (traversal.GetInfo().IsDirectory()) 227 directories.push(current.value()); 228 else 229 success = (unlink(current.value().c_str()) == 0); 230 } 231 232 while (success && !directories.empty()) { 233 FilePath dir = FilePath(directories.top()); 234 directories.pop(); 235 success = (rmdir(dir.value().c_str()) == 0); 236 } 237 return success; 238 } 239 240 bool ReplaceFile(const FilePath& from_path, 241 const FilePath& to_path, 242 File::Error* error) { 243 ThreadRestrictions::AssertIOAllowed(); 244 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) 245 return true; 246 if (error) 247 *error = File::OSErrorToFileError(errno); 248 return false; 249 } 250 251 bool CopyDirectory(const FilePath& from_path, 252 const FilePath& to_path, 253 bool recursive) { 254 ThreadRestrictions::AssertIOAllowed(); 255 // Some old callers of CopyDirectory want it to support wildcards. 256 // After some discussion, we decided to fix those callers. 257 // Break loudly here if anyone tries to do this. 258 DCHECK(to_path.value().find('*') == std::string::npos); 259 DCHECK(from_path.value().find('*') == std::string::npos); 260 261 if (from_path.value().size() >= PATH_MAX) { 262 return false; 263 } 264 265 // This function does not properly handle destinations within the source 266 FilePath real_to_path = to_path; 267 if (PathExists(real_to_path)) { 268 real_to_path = MakeAbsoluteFilePath(real_to_path); 269 if (real_to_path.empty()) 270 return false; 271 } else { 272 real_to_path = MakeAbsoluteFilePath(real_to_path.DirName()); 273 if (real_to_path.empty()) 274 return false; 275 } 276 FilePath real_from_path = MakeAbsoluteFilePath(from_path); 277 if (real_from_path.empty()) 278 return false; 279 if (real_to_path.value().size() >= real_from_path.value().size() && 280 real_to_path.value().compare(0, real_from_path.value().size(), 281 real_from_path.value()) == 0) { 282 return false; 283 } 284 285 int traverse_type = FileEnumerator::FILES | FileEnumerator::SHOW_SYM_LINKS; 286 if (recursive) 287 traverse_type |= FileEnumerator::DIRECTORIES; 288 FileEnumerator traversal(from_path, recursive, traverse_type); 289 290 // We have to mimic windows behavior here. |to_path| may not exist yet, 291 // start the loop with |to_path|. 292 struct stat from_stat; 293 FilePath current = from_path; 294 if (stat(from_path.value().c_str(), &from_stat) < 0) { 295 DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: " 296 << from_path.value() << " errno = " << errno; 297 return false; 298 } 299 struct stat to_path_stat; 300 FilePath from_path_base = from_path; 301 if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 && 302 S_ISDIR(to_path_stat.st_mode)) { 303 // If the destination already exists and is a directory, then the 304 // top level of source needs to be copied. 305 from_path_base = from_path.DirName(); 306 } 307 308 // The Windows version of this function assumes that non-recursive calls 309 // will always have a directory for from_path. 310 // TODO(maruel): This is not necessary anymore. 311 DCHECK(recursive || S_ISDIR(from_stat.st_mode)); 312 313 bool success = true; 314 while (success && !current.empty()) { 315 // current is the source path, including from_path, so append 316 // the suffix after from_path to to_path to create the target_path. 317 FilePath target_path(to_path); 318 if (from_path_base != current) { 319 if (!from_path_base.AppendRelativePath(current, &target_path)) { 320 success = false; 321 break; 322 } 323 } 324 325 if (S_ISDIR(from_stat.st_mode)) { 326 if (mkdir(target_path.value().c_str(), 327 (from_stat.st_mode & 01777) | S_IRUSR | S_IXUSR | S_IWUSR) != 328 0 && 329 errno != EEXIST) { 330 DLOG(ERROR) << "CopyDirectory() couldn't create directory: " 331 << target_path.value() << " errno = " << errno; 332 success = false; 333 } 334 } else if (S_ISREG(from_stat.st_mode)) { 335 if (!CopyFile(current, target_path)) { 336 DLOG(ERROR) << "CopyDirectory() couldn't create file: " 337 << target_path.value(); 338 success = false; 339 } 340 } else { 341 DLOG(WARNING) << "CopyDirectory() skipping non-regular file: " 342 << current.value(); 343 } 344 345 current = traversal.Next(); 346 if (!current.empty()) 347 from_stat = traversal.GetInfo().stat(); 348 } 349 350 return success; 351 } 352 #endif // !defined(OS_NACL_NONSFI) 353 354 bool SetNonBlocking(int fd) { 355 const int flags = fcntl(fd, F_GETFL); 356 if (flags == -1) 357 return false; 358 if (flags & O_NONBLOCK) 359 return true; 360 if (HANDLE_EINTR(fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) 361 return false; 362 return true; 363 } 364 365 bool PathExists(const FilePath& path) { 366 ThreadRestrictions::AssertIOAllowed(); 367 #if defined(OS_ANDROID) 368 if (path.IsContentUri()) { 369 return ContentUriExists(path); 370 } 371 #endif 372 return access(path.value().c_str(), F_OK) == 0; 373 } 374 375 #if !defined(OS_NACL_NONSFI) 376 bool PathIsWritable(const FilePath& path) { 377 ThreadRestrictions::AssertIOAllowed(); 378 return access(path.value().c_str(), W_OK) == 0; 379 } 380 #endif // !defined(OS_NACL_NONSFI) 381 382 bool DirectoryExists(const FilePath& path) { 383 ThreadRestrictions::AssertIOAllowed(); 384 stat_wrapper_t file_info; 385 if (CallStat(path.value().c_str(), &file_info) == 0) 386 return S_ISDIR(file_info.st_mode); 387 return false; 388 } 389 390 bool ReadFromFD(int fd, char* buffer, size_t bytes) { 391 size_t total_read = 0; 392 while (total_read < bytes) { 393 ssize_t bytes_read = 394 HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read)); 395 if (bytes_read <= 0) 396 break; 397 total_read += bytes_read; 398 } 399 return total_read == bytes; 400 } 401 402 #if !defined(OS_NACL_NONSFI) 403 bool CreateSymbolicLink(const FilePath& target_path, 404 const FilePath& symlink_path) { 405 DCHECK(!symlink_path.empty()); 406 DCHECK(!target_path.empty()); 407 return ::symlink(target_path.value().c_str(), 408 symlink_path.value().c_str()) != -1; 409 } 410 411 bool ReadSymbolicLink(const FilePath& symlink_path, FilePath* target_path) { 412 DCHECK(!symlink_path.empty()); 413 DCHECK(target_path); 414 char buf[PATH_MAX]; 415 ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf)); 416 417 if (count <= 0) { 418 target_path->clear(); 419 return false; 420 } 421 422 *target_path = FilePath(FilePath::StringType(buf, count)); 423 return true; 424 } 425 426 bool GetPosixFilePermissions(const FilePath& path, int* mode) { 427 ThreadRestrictions::AssertIOAllowed(); 428 DCHECK(mode); 429 430 stat_wrapper_t file_info; 431 // Uses stat(), because on symbolic link, lstat() does not return valid 432 // permission bits in st_mode 433 if (CallStat(path.value().c_str(), &file_info) != 0) 434 return false; 435 436 *mode = file_info.st_mode & FILE_PERMISSION_MASK; 437 return true; 438 } 439 440 bool SetPosixFilePermissions(const FilePath& path, 441 int mode) { 442 ThreadRestrictions::AssertIOAllowed(); 443 DCHECK_EQ(mode & ~FILE_PERMISSION_MASK, 0); 444 445 // Calls stat() so that we can preserve the higher bits like S_ISGID. 446 stat_wrapper_t stat_buf; 447 if (CallStat(path.value().c_str(), &stat_buf) != 0) 448 return false; 449 450 // Clears the existing permission bits, and adds the new ones. 451 mode_t updated_mode_bits = stat_buf.st_mode & ~FILE_PERMISSION_MASK; 452 updated_mode_bits |= mode & FILE_PERMISSION_MASK; 453 454 if (HANDLE_EINTR(chmod(path.value().c_str(), updated_mode_bits)) != 0) 455 return false; 456 457 return true; 458 } 459 460 bool ExecutableExistsInPath(Environment* env, 461 const FilePath::StringType& executable) { 462 std::string path; 463 if (!env->GetVar("PATH", &path)) { 464 LOG(ERROR) << "No $PATH variable. Assuming no " << executable << "."; 465 return false; 466 } 467 468 for (const StringPiece& cur_path : 469 SplitStringPiece(path, ":", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY)) { 470 FilePath file(cur_path); 471 int permissions; 472 if (GetPosixFilePermissions(file.Append(executable), &permissions) && 473 (permissions & FILE_PERMISSION_EXECUTE_BY_USER)) 474 return true; 475 } 476 return false; 477 } 478 479 #if !defined(OS_MACOSX) 480 // This is implemented in file_util_mac.mm for Mac. 481 bool GetTempDir(FilePath* path) { 482 const char* tmp = getenv("TMPDIR"); 483 if (tmp) { 484 *path = FilePath(tmp); 485 } else { 486 #if defined(OS_ANDROID) 487 return PathService::Get(base::DIR_CACHE, path); 488 #elif defined(__ANDROID__) 489 *path = FilePath("/data/local/tmp"); 490 #else 491 *path = FilePath("/tmp"); 492 #endif 493 } 494 return true; 495 } 496 #endif // !defined(OS_MACOSX) 497 498 #if !defined(OS_MACOSX) // Mac implementation is in file_util_mac.mm. 499 FilePath GetHomeDir() { 500 #if defined(OS_CHROMEOS) 501 if (SysInfo::IsRunningOnChromeOS()) { 502 // On Chrome OS chrome::DIR_USER_DATA is overridden with a primary user 503 // homedir once it becomes available. Return / as the safe option. 504 return FilePath("/"); 505 } 506 #endif 507 508 const char* home_dir = getenv("HOME"); 509 if (home_dir && home_dir[0]) 510 return FilePath(home_dir); 511 512 #if defined(OS_ANDROID) 513 DLOG(WARNING) << "OS_ANDROID: Home directory lookup not yet implemented."; 514 #endif 515 516 FilePath rv; 517 if (GetTempDir(&rv)) 518 return rv; 519 520 // Last resort. 521 return FilePath("/tmp"); 522 } 523 #endif // !defined(OS_MACOSX) 524 525 bool CreateTemporaryFile(FilePath* path) { 526 ThreadRestrictions::AssertIOAllowed(); // For call to close(). 527 FilePath directory; 528 if (!GetTempDir(&directory)) 529 return false; 530 int fd = CreateAndOpenFdForTemporaryFile(directory, path); 531 if (fd < 0) 532 return false; 533 close(fd); 534 return true; 535 } 536 537 FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { 538 int fd = CreateAndOpenFdForTemporaryFile(dir, path); 539 if (fd < 0) 540 return NULL; 541 542 FILE* file = fdopen(fd, "a+"); 543 if (!file) 544 close(fd); 545 return file; 546 } 547 548 bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) { 549 ThreadRestrictions::AssertIOAllowed(); // For call to close(). 550 int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file); 551 return ((fd >= 0) && !IGNORE_EINTR(close(fd))); 552 } 553 554 static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir, 555 const FilePath::StringType& name_tmpl, 556 FilePath* new_dir) { 557 ThreadRestrictions::AssertIOAllowed(); // For call to mkdtemp(). 558 DCHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos) 559 << "Directory name template must contain \"XXXXXX\"."; 560 561 FilePath sub_dir = base_dir.Append(name_tmpl); 562 std::string sub_dir_string = sub_dir.value(); 563 564 // this should be OK since mkdtemp just replaces characters in place 565 char* buffer = const_cast<char*>(sub_dir_string.c_str()); 566 char* dtemp = mkdtemp(buffer); 567 if (!dtemp) { 568 DPLOG(ERROR) << "mkdtemp"; 569 return false; 570 } 571 *new_dir = FilePath(dtemp); 572 return true; 573 } 574 575 bool CreateTemporaryDirInDir(const FilePath& base_dir, 576 const FilePath::StringType& prefix, 577 FilePath* new_dir) { 578 FilePath::StringType mkdtemp_template = prefix; 579 mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX")); 580 return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir); 581 } 582 583 bool CreateNewTempDirectory(const FilePath::StringType& /*prefix*/, 584 FilePath* new_temp_path) { 585 FilePath tmpdir; 586 if (!GetTempDir(&tmpdir)) 587 return false; 588 589 return CreateTemporaryDirInDirImpl(tmpdir, TempFileName(), new_temp_path); 590 } 591 592 bool CreateDirectoryAndGetError(const FilePath& full_path, 593 File::Error* error) { 594 ThreadRestrictions::AssertIOAllowed(); // For call to mkdir(). 595 std::vector<FilePath> subpaths; 596 597 // Collect a list of all parent directories. 598 FilePath last_path = full_path; 599 subpaths.push_back(full_path); 600 for (FilePath path = full_path.DirName(); 601 path.value() != last_path.value(); path = path.DirName()) { 602 subpaths.push_back(path); 603 last_path = path; 604 } 605 606 // Iterate through the parents and create the missing ones. 607 for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin(); 608 i != subpaths.rend(); ++i) { 609 if (DirectoryExists(*i)) 610 continue; 611 if (mkdir(i->value().c_str(), 0700) == 0) 612 continue; 613 // Mkdir failed, but it might have failed with EEXIST, or some other error 614 // due to the the directory appearing out of thin air. This can occur if 615 // two processes are trying to create the same file system tree at the same 616 // time. Check to see if it exists and make sure it is a directory. 617 int saved_errno = errno; 618 if (!DirectoryExists(*i)) { 619 if (error) 620 *error = File::OSErrorToFileError(saved_errno); 621 return false; 622 } 623 } 624 return true; 625 } 626 627 bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) { 628 FilePath real_path_result; 629 if (!RealPath(path, &real_path_result)) 630 return false; 631 632 // To be consistant with windows, fail if |real_path_result| is a 633 // directory. 634 stat_wrapper_t file_info; 635 if (CallStat(real_path_result.value().c_str(), &file_info) != 0 || 636 S_ISDIR(file_info.st_mode)) 637 return false; 638 639 *normalized_path = real_path_result; 640 return true; 641 } 642 643 // TODO(rkc): Refactor GetFileInfo and FileEnumerator to handle symlinks 644 // correctly. http://code.google.com/p/chromium-os/issues/detail?id=15948 645 bool IsLink(const FilePath& file_path) { 646 stat_wrapper_t st; 647 // If we can't lstat the file, it's safe to assume that the file won't at 648 // least be a 'followable' link. 649 if (CallLstat(file_path.value().c_str(), &st) != 0) 650 return false; 651 652 if (S_ISLNK(st.st_mode)) 653 return true; 654 else 655 return false; 656 } 657 658 bool GetFileInfo(const FilePath& file_path, File::Info* results) { 659 stat_wrapper_t file_info; 660 #if defined(OS_ANDROID) 661 if (file_path.IsContentUri()) { 662 File file = OpenContentUriForRead(file_path); 663 if (!file.IsValid()) 664 return false; 665 return file.GetInfo(results); 666 } else { 667 #endif // defined(OS_ANDROID) 668 if (CallStat(file_path.value().c_str(), &file_info) != 0) 669 return false; 670 #if defined(OS_ANDROID) 671 } 672 #endif // defined(OS_ANDROID) 673 674 results->FromStat(file_info); 675 return true; 676 } 677 #endif // !defined(OS_NACL_NONSFI) 678 679 FILE* OpenFile(const FilePath& filename, const char* mode) { 680 ThreadRestrictions::AssertIOAllowed(); 681 FILE* result = NULL; 682 do { 683 result = fopen(filename.value().c_str(), mode); 684 } while (!result && errno == EINTR); 685 return result; 686 } 687 688 // NaCl doesn't implement system calls to open files directly. 689 #if !defined(OS_NACL) 690 FILE* FileToFILE(File file, const char* mode) { 691 FILE* stream = fdopen(file.GetPlatformFile(), mode); 692 if (stream) 693 file.TakePlatformFile(); 694 return stream; 695 } 696 #endif // !defined(OS_NACL) 697 698 int ReadFile(const FilePath& filename, char* data, int max_size) { 699 ThreadRestrictions::AssertIOAllowed(); 700 int fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY)); 701 if (fd < 0) 702 return -1; 703 704 ssize_t bytes_read = HANDLE_EINTR(read(fd, data, max_size)); 705 if (IGNORE_EINTR(close(fd)) < 0) 706 return -1; 707 return bytes_read; 708 } 709 710 int WriteFile(const FilePath& filename, const char* data, int size) { 711 ThreadRestrictions::AssertIOAllowed(); 712 int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666)); 713 if (fd < 0) 714 return -1; 715 716 int bytes_written = WriteFileDescriptor(fd, data, size) ? size : -1; 717 if (IGNORE_EINTR(close(fd)) < 0) 718 return -1; 719 return bytes_written; 720 } 721 722 bool WriteFileDescriptor(const int fd, const char* data, int size) { 723 // Allow for partial writes. 724 ssize_t bytes_written_total = 0; 725 for (ssize_t bytes_written_partial = 0; bytes_written_total < size; 726 bytes_written_total += bytes_written_partial) { 727 bytes_written_partial = 728 HANDLE_EINTR(write(fd, data + bytes_written_total, 729 size - bytes_written_total)); 730 if (bytes_written_partial < 0) 731 return false; 732 } 733 734 return true; 735 } 736 737 #if !defined(OS_NACL_NONSFI) 738 739 bool AppendToFile(const FilePath& filename, const char* data, int size) { 740 ThreadRestrictions::AssertIOAllowed(); 741 bool ret = true; 742 int fd = HANDLE_EINTR(open(filename.value().c_str(), O_WRONLY | O_APPEND)); 743 if (fd < 0) { 744 VPLOG(1) << "Unable to create file " << filename.value(); 745 return false; 746 } 747 748 // This call will either write all of the data or return false. 749 if (!WriteFileDescriptor(fd, data, size)) { 750 VPLOG(1) << "Error while writing to file " << filename.value(); 751 ret = false; 752 } 753 754 if (IGNORE_EINTR(close(fd)) < 0) { 755 VPLOG(1) << "Error while closing file " << filename.value(); 756 return false; 757 } 758 759 return ret; 760 } 761 762 // Gets the current working directory for the process. 763 bool GetCurrentDirectory(FilePath* dir) { 764 // getcwd can return ENOENT, which implies it checks against the disk. 765 ThreadRestrictions::AssertIOAllowed(); 766 767 char system_buffer[PATH_MAX] = ""; 768 if (!getcwd(system_buffer, sizeof(system_buffer))) { 769 NOTREACHED(); 770 return false; 771 } 772 *dir = FilePath(system_buffer); 773 return true; 774 } 775 776 // Sets the current working directory for the process. 777 bool SetCurrentDirectory(const FilePath& path) { 778 ThreadRestrictions::AssertIOAllowed(); 779 int ret = chdir(path.value().c_str()); 780 return !ret; 781 } 782 783 bool VerifyPathControlledByUser(const FilePath& base, 784 const FilePath& path, 785 uid_t owner_uid, 786 const std::set<gid_t>& group_gids) { 787 if (base != path && !base.IsParent(path)) { 788 DLOG(ERROR) << "|base| must be a subdirectory of |path|. base = \"" 789 << base.value() << "\", path = \"" << path.value() << "\""; 790 return false; 791 } 792 793 std::vector<FilePath::StringType> base_components; 794 std::vector<FilePath::StringType> path_components; 795 796 base.GetComponents(&base_components); 797 path.GetComponents(&path_components); 798 799 std::vector<FilePath::StringType>::const_iterator ib, ip; 800 for (ib = base_components.begin(), ip = path_components.begin(); 801 ib != base_components.end(); ++ib, ++ip) { 802 // |base| must be a subpath of |path|, so all components should match. 803 // If these CHECKs fail, look at the test that base is a parent of 804 // path at the top of this function. 805 DCHECK(ip != path_components.end()); 806 DCHECK(*ip == *ib); 807 } 808 809 FilePath current_path = base; 810 if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gids)) 811 return false; 812 813 for (; ip != path_components.end(); ++ip) { 814 current_path = current_path.Append(*ip); 815 if (!VerifySpecificPathControlledByUser( 816 current_path, owner_uid, group_gids)) 817 return false; 818 } 819 return true; 820 } 821 822 #if defined(OS_MACOSX) && !defined(OS_IOS) 823 bool VerifyPathControlledByAdmin(const FilePath& path) { 824 const unsigned kRootUid = 0; 825 const FilePath kFileSystemRoot("/"); 826 827 // The name of the administrator group on mac os. 828 const char* const kAdminGroupNames[] = { 829 "admin", 830 "wheel" 831 }; 832 833 // Reading the groups database may touch the file system. 834 ThreadRestrictions::AssertIOAllowed(); 835 836 std::set<gid_t> allowed_group_ids; 837 for (int i = 0, ie = arraysize(kAdminGroupNames); i < ie; ++i) { 838 struct group *group_record = getgrnam(kAdminGroupNames[i]); 839 if (!group_record) { 840 DPLOG(ERROR) << "Could not get the group ID of group \"" 841 << kAdminGroupNames[i] << "\"."; 842 continue; 843 } 844 845 allowed_group_ids.insert(group_record->gr_gid); 846 } 847 848 return VerifyPathControlledByUser( 849 kFileSystemRoot, path, kRootUid, allowed_group_ids); 850 } 851 #endif // defined(OS_MACOSX) && !defined(OS_IOS) 852 853 int GetMaximumPathComponentLength(const FilePath& path) { 854 ThreadRestrictions::AssertIOAllowed(); 855 return pathconf(path.value().c_str(), _PC_NAME_MAX); 856 } 857 858 #if !defined(OS_ANDROID) 859 // This is implemented in file_util_android.cc for that platform. 860 bool GetShmemTempDir(bool executable, FilePath* path) { 861 #if defined(OS_LINUX) 862 bool use_dev_shm = true; 863 if (executable) { 864 static const bool s_dev_shm_executable = DetermineDevShmExecutable(); 865 use_dev_shm = s_dev_shm_executable; 866 } 867 if (use_dev_shm) { 868 *path = FilePath("/dev/shm"); 869 return true; 870 } 871 #else 872 (void)executable; // Avoid unused warning when !defined(OS_LINUX). 873 #endif 874 return GetTempDir(path); 875 } 876 #endif // !defined(OS_ANDROID) 877 878 #if !defined(OS_MACOSX) 879 // Mac has its own implementation, this is for all other Posix systems. 880 bool CopyFile(const FilePath& from_path, const FilePath& to_path) { 881 ThreadRestrictions::AssertIOAllowed(); 882 File infile; 883 #if defined(OS_ANDROID) 884 if (from_path.IsContentUri()) { 885 infile = OpenContentUriForRead(from_path); 886 } else { 887 infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ); 888 } 889 #else 890 infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ); 891 #endif 892 if (!infile.IsValid()) 893 return false; 894 895 File outfile(to_path, File::FLAG_WRITE | File::FLAG_CREATE_ALWAYS); 896 if (!outfile.IsValid()) 897 return false; 898 899 const size_t kBufferSize = 32768; 900 std::vector<char> buffer(kBufferSize); 901 bool result = true; 902 903 while (result) { 904 ssize_t bytes_read = infile.ReadAtCurrentPos(&buffer[0], buffer.size()); 905 if (bytes_read < 0) { 906 result = false; 907 break; 908 } 909 if (bytes_read == 0) 910 break; 911 // Allow for partial writes 912 ssize_t bytes_written_per_read = 0; 913 do { 914 ssize_t bytes_written_partial = outfile.WriteAtCurrentPos( 915 &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read); 916 if (bytes_written_partial < 0) { 917 result = false; 918 break; 919 } 920 bytes_written_per_read += bytes_written_partial; 921 } while (bytes_written_per_read < bytes_read); 922 } 923 924 return result; 925 } 926 #endif // !defined(OS_MACOSX) 927 928 // ----------------------------------------------------------------------------- 929 930 namespace internal { 931 932 bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) { 933 ThreadRestrictions::AssertIOAllowed(); 934 // Windows compatibility: if to_path exists, from_path and to_path 935 // must be the same type, either both files, or both directories. 936 stat_wrapper_t to_file_info; 937 if (CallStat(to_path.value().c_str(), &to_file_info) == 0) { 938 stat_wrapper_t from_file_info; 939 if (CallStat(from_path.value().c_str(), &from_file_info) == 0) { 940 if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode)) 941 return false; 942 } else { 943 return false; 944 } 945 } 946 947 if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) 948 return true; 949 950 if (!CopyDirectory(from_path, to_path, true)) 951 return false; 952 953 DeleteFile(from_path, true); 954 return true; 955 } 956 957 } // namespace internal 958 959 #endif // !defined(OS_NACL_NONSFI) 960 } // namespace base 961