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