1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/file_util_posix.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,504 @@ 1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "base/file_util.h" 1.9 + 1.10 +#include <dirent.h> 1.11 +#include <errno.h> 1.12 +#include <fcntl.h> 1.13 +#include <fnmatch.h> 1.14 +#ifndef ANDROID 1.15 +#include <fts.h> 1.16 +#endif 1.17 +#include <libgen.h> 1.18 +#include <stdio.h> 1.19 +#include <string.h> 1.20 +#include <sys/errno.h> 1.21 +#include <sys/mman.h> 1.22 +#define _DARWIN_USE_64_BIT_INODE // Use 64-bit inode data structures 1.23 +#include <sys/stat.h> 1.24 +#include <sys/types.h> 1.25 +#include <time.h> 1.26 +#include <unistd.h> 1.27 + 1.28 +#include <fstream> 1.29 +#include <string> 1.30 +#include <vector> 1.31 + 1.32 +#include "base/basictypes.h" 1.33 +#include "base/eintr_wrapper.h" 1.34 +#include "base/file_path.h" 1.35 +#include "base/logging.h" 1.36 +#include "base/string_util.h" 1.37 +#include "base/time.h" 1.38 + 1.39 +namespace file_util { 1.40 + 1.41 +#if defined(GOOGLE_CHROME_BUILD) 1.42 +static const char* kTempFileName = "com.google.chrome.XXXXXX"; 1.43 +#else 1.44 +static const char* kTempFileName = "org.chromium.XXXXXX"; 1.45 +#endif 1.46 + 1.47 +bool AbsolutePath(FilePath* path) { 1.48 + char full_path[PATH_MAX]; 1.49 + if (realpath(path->value().c_str(), full_path) == NULL) 1.50 + return false; 1.51 + *path = FilePath(full_path); 1.52 + return true; 1.53 +} 1.54 + 1.55 +// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*" 1.56 +// which works both with and without the recursive flag. I'm not sure we need 1.57 +// that functionality. If not, remove from file_util_win.cc, otherwise add it 1.58 +// here. 1.59 +bool Delete(const FilePath& path, bool recursive) { 1.60 + const char* path_str = path.value().c_str(); 1.61 + struct stat file_info; 1.62 + int test = stat(path_str, &file_info); 1.63 + if (test != 0) { 1.64 + // The Windows version defines this condition as success. 1.65 + bool ret = (errno == ENOENT || errno == ENOTDIR); 1.66 + return ret; 1.67 + } 1.68 + if (!S_ISDIR(file_info.st_mode)) 1.69 + return (unlink(path_str) == 0); 1.70 + if (!recursive) 1.71 + return (rmdir(path_str) == 0); 1.72 + 1.73 +#ifdef ANDROID 1.74 + // XXX Need ftsless impl for bionic 1.75 + return false; 1.76 +#else 1.77 + bool success = true; 1.78 + int ftsflags = FTS_PHYSICAL | FTS_NOSTAT; 1.79 + char top_dir[PATH_MAX]; 1.80 + if (base::strlcpy(top_dir, path_str, 1.81 + arraysize(top_dir)) >= arraysize(top_dir)) { 1.82 + return false; 1.83 + } 1.84 + char* dir_list[2] = { top_dir, NULL }; 1.85 + FTS* fts = fts_open(dir_list, ftsflags, NULL); 1.86 + if (fts) { 1.87 + FTSENT* fts_ent = fts_read(fts); 1.88 + while (success && fts_ent != NULL) { 1.89 + switch (fts_ent->fts_info) { 1.90 + case FTS_DNR: 1.91 + case FTS_ERR: 1.92 + // log error 1.93 + success = false; 1.94 + continue; 1.95 + break; 1.96 + case FTS_DP: 1.97 + success = (rmdir(fts_ent->fts_accpath) == 0); 1.98 + break; 1.99 + case FTS_D: 1.100 + break; 1.101 + case FTS_NSOK: 1.102 + case FTS_F: 1.103 + case FTS_SL: 1.104 + case FTS_SLNONE: 1.105 + success = (unlink(fts_ent->fts_accpath) == 0); 1.106 + break; 1.107 + default: 1.108 + DCHECK(false); 1.109 + break; 1.110 + } 1.111 + fts_ent = fts_read(fts); 1.112 + } 1.113 + fts_close(fts); 1.114 + } 1.115 + return success; 1.116 +#endif 1.117 +} 1.118 + 1.119 +bool Move(const FilePath& from_path, const FilePath& to_path) { 1.120 + if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0) 1.121 + return true; 1.122 + 1.123 + if (!CopyDirectory(from_path, to_path, true)) 1.124 + return false; 1.125 + 1.126 + Delete(from_path, true); 1.127 + return true; 1.128 +} 1.129 + 1.130 +bool CopyDirectory(const FilePath& from_path, 1.131 + const FilePath& to_path, 1.132 + bool recursive) { 1.133 + // Some old callers of CopyDirectory want it to support wildcards. 1.134 + // After some discussion, we decided to fix those callers. 1.135 + // Break loudly here if anyone tries to do this. 1.136 + // TODO(evanm): remove this once we're sure it's ok. 1.137 + DCHECK(to_path.value().find('*') == std::string::npos); 1.138 + DCHECK(from_path.value().find('*') == std::string::npos); 1.139 + 1.140 + char top_dir[PATH_MAX]; 1.141 + if (base::strlcpy(top_dir, from_path.value().c_str(), 1.142 + arraysize(top_dir)) >= arraysize(top_dir)) { 1.143 + return false; 1.144 + } 1.145 + 1.146 +#ifdef ANDROID 1.147 + // XXX Need ftsless impl for bionic 1.148 + return false; 1.149 +#else 1.150 + char* dir_list[] = { top_dir, NULL }; 1.151 + FTS* fts = fts_open(dir_list, FTS_PHYSICAL | FTS_NOSTAT, NULL); 1.152 + if (!fts) { 1.153 + CHROMIUM_LOG(ERROR) << "fts_open failed: " << strerror(errno); 1.154 + return false; 1.155 + } 1.156 + 1.157 + int error = 0; 1.158 + FTSENT* ent; 1.159 + while (!error && (ent = fts_read(fts)) != NULL) { 1.160 + // ent->fts_path is the source path, including from_path, so paste 1.161 + // the suffix after from_path onto to_path to create the target_path. 1.162 + std::string suffix(&ent->fts_path[from_path.value().size()]); 1.163 + // Strip the leading '/' (if any). 1.164 + if (!suffix.empty()) { 1.165 + DCHECK_EQ('/', suffix[0]); 1.166 + suffix.erase(0, 1); 1.167 + } 1.168 + const FilePath target_path = to_path.Append(suffix); 1.169 + switch (ent->fts_info) { 1.170 + case FTS_D: // Preorder directory. 1.171 + // If we encounter a subdirectory in a non-recursive copy, prune it 1.172 + // from the traversal. 1.173 + if (!recursive && ent->fts_level > 0) { 1.174 + if (fts_set(fts, ent, FTS_SKIP) != 0) 1.175 + error = errno; 1.176 + continue; 1.177 + } 1.178 + 1.179 + // Try creating the target dir, continuing on it if it exists already. 1.180 + // Rely on the user's umask to produce correct permissions. 1.181 + if (mkdir(target_path.value().c_str(), 0777) != 0) { 1.182 + if (errno != EEXIST) 1.183 + error = errno; 1.184 + } 1.185 + break; 1.186 + case FTS_F: // Regular file. 1.187 + case FTS_NSOK: // File, no stat info requested. 1.188 + errno = 0; 1.189 + if (!CopyFile(FilePath(ent->fts_path), target_path)) 1.190 + error = errno ? errno : EINVAL; 1.191 + break; 1.192 + case FTS_DP: // Postorder directory. 1.193 + case FTS_DOT: // "." or ".." 1.194 + // Skip it. 1.195 + continue; 1.196 + case FTS_DC: // Directory causing a cycle. 1.197 + // Skip this branch. 1.198 + if (fts_set(fts, ent, FTS_SKIP) != 0) 1.199 + error = errno; 1.200 + break; 1.201 + case FTS_DNR: // Directory cannot be read. 1.202 + case FTS_ERR: // Error. 1.203 + case FTS_NS: // Stat failed. 1.204 + // Abort with the error. 1.205 + error = ent->fts_errno; 1.206 + break; 1.207 + case FTS_SL: // Symlink. 1.208 + case FTS_SLNONE: // Symlink with broken target. 1.209 + CHROMIUM_LOG(WARNING) << "CopyDirectory() skipping symbolic link: " << 1.210 + ent->fts_path; 1.211 + continue; 1.212 + case FTS_DEFAULT: // Some other sort of file. 1.213 + CHROMIUM_LOG(WARNING) << "CopyDirectory() skipping file of unknown type: " << 1.214 + ent->fts_path; 1.215 + continue; 1.216 + default: 1.217 + NOTREACHED(); 1.218 + continue; // Hope for the best! 1.219 + } 1.220 + } 1.221 + // fts_read may have returned NULL and set errno to indicate an error. 1.222 + if (!error && errno != 0) 1.223 + error = errno; 1.224 + 1.225 + if (!fts_close(fts)) { 1.226 + // If we already have an error, let's use that error instead of the error 1.227 + // fts_close set. 1.228 + if (!error) 1.229 + error = errno; 1.230 + } 1.231 + 1.232 + if (error) { 1.233 + CHROMIUM_LOG(ERROR) << "CopyDirectory(): " << strerror(error); 1.234 + return false; 1.235 + } 1.236 + return true; 1.237 +#endif 1.238 +} 1.239 + 1.240 +bool PathExists(const FilePath& path) { 1.241 + struct stat file_info; 1.242 + return (stat(path.value().c_str(), &file_info) == 0); 1.243 +} 1.244 + 1.245 +bool PathIsWritable(const FilePath& path) { 1.246 + FilePath test_path(path); 1.247 + struct stat file_info; 1.248 + if (stat(test_path.value().c_str(), &file_info) != 0) { 1.249 + // If the path doesn't exist, test the parent dir. 1.250 + test_path = test_path.DirName(); 1.251 + // If the parent dir doesn't exist, then return false (the path is not 1.252 + // directly writable). 1.253 + if (stat(test_path.value().c_str(), &file_info) != 0) 1.254 + return false; 1.255 + } 1.256 + if (S_IWOTH & file_info.st_mode) 1.257 + return true; 1.258 + if (getegid() == file_info.st_gid && (S_IWGRP & file_info.st_mode)) 1.259 + return true; 1.260 + if (geteuid() == file_info.st_uid && (S_IWUSR & file_info.st_mode)) 1.261 + return true; 1.262 + return false; 1.263 +} 1.264 + 1.265 +bool DirectoryExists(const FilePath& path) { 1.266 + struct stat file_info; 1.267 + if (stat(path.value().c_str(), &file_info) == 0) 1.268 + return S_ISDIR(file_info.st_mode); 1.269 + return false; 1.270 +} 1.271 + 1.272 +bool ReadFromFD(int fd, char* buffer, size_t bytes) { 1.273 + size_t total_read = 0; 1.274 + while (total_read < bytes) { 1.275 + ssize_t bytes_read = 1.276 + HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read)); 1.277 + if (bytes_read <= 0) 1.278 + break; 1.279 + total_read += bytes_read; 1.280 + } 1.281 + return total_read == bytes; 1.282 +} 1.283 + 1.284 +// Creates and opens a temporary file in |directory|, returning the 1.285 +// file descriptor. |path| is set to the temporary file path. 1.286 +// Note TODO(erikkay) comment in header for BlahFileName() calls; the 1.287 +// intent is to rename these files BlahFile() (since they create 1.288 +// files, not filenames). This function does NOT unlink() the file. 1.289 +int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) { 1.290 + *path = directory.Append(kTempFileName); 1.291 + const std::string& tmpdir_string = path->value(); 1.292 + // this should be OK since mkstemp just replaces characters in place 1.293 + char* buffer = const_cast<char*>(tmpdir_string.c_str()); 1.294 + 1.295 + return mkstemp(buffer); 1.296 +} 1.297 + 1.298 +bool CreateTemporaryFileName(FilePath* path) { 1.299 + FilePath directory; 1.300 + if (!GetTempDir(&directory)) 1.301 + return false; 1.302 + int fd = CreateAndOpenFdForTemporaryFile(directory, path); 1.303 + if (fd < 0) 1.304 + return false; 1.305 + close(fd); 1.306 + return true; 1.307 +} 1.308 + 1.309 +FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) { 1.310 + FilePath directory; 1.311 + if (!GetShmemTempDir(&directory)) 1.312 + return NULL; 1.313 + 1.314 + return CreateAndOpenTemporaryFileInDir(directory, path); 1.315 +} 1.316 + 1.317 +FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) { 1.318 + int fd = CreateAndOpenFdForTemporaryFile(dir, path); 1.319 + if (fd < 0) 1.320 + return NULL; 1.321 + 1.322 + return fdopen(fd, "a+"); 1.323 +} 1.324 + 1.325 +bool CreateTemporaryFileNameInDir(const std::wstring& dir, 1.326 + std::wstring* temp_file) { 1.327 + // Not implemented yet. 1.328 + NOTREACHED(); 1.329 + return false; 1.330 +} 1.331 + 1.332 +bool CreateNewTempDirectory(const FilePath::StringType& prefix, 1.333 + FilePath* new_temp_path) { 1.334 + FilePath tmpdir; 1.335 + if (!GetTempDir(&tmpdir)) 1.336 + return false; 1.337 + tmpdir = tmpdir.Append(kTempFileName); 1.338 + std::string tmpdir_string = tmpdir.value(); 1.339 +#ifdef ANDROID 1.340 + char* dtemp = NULL; 1.341 +#else 1.342 + // this should be OK since mkdtemp just replaces characters in place 1.343 + char* buffer = const_cast<char*>(tmpdir_string.c_str()); 1.344 + char* dtemp = mkdtemp(buffer); 1.345 +#endif 1.346 + if (!dtemp) 1.347 + return false; 1.348 + *new_temp_path = FilePath(dtemp); 1.349 + return true; 1.350 +} 1.351 + 1.352 +bool CreateDirectory(const FilePath& full_path) { 1.353 + std::vector<FilePath> subpaths; 1.354 + 1.355 + // Collect a list of all parent directories. 1.356 + FilePath last_path = full_path; 1.357 + subpaths.push_back(full_path); 1.358 + for (FilePath path = full_path.DirName(); 1.359 + path.value() != last_path.value(); path = path.DirName()) { 1.360 + subpaths.push_back(path); 1.361 + last_path = path; 1.362 + } 1.363 + 1.364 + // Iterate through the parents and create the missing ones. 1.365 + for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin(); 1.366 + i != subpaths.rend(); ++i) { 1.367 + if (!DirectoryExists(*i)) { 1.368 + if (mkdir(i->value().c_str(), 0777) != 0) 1.369 + return false; 1.370 + } 1.371 + } 1.372 + return true; 1.373 +} 1.374 + 1.375 +bool GetFileInfo(const FilePath& file_path, FileInfo* results) { 1.376 + struct stat file_info; 1.377 + if (stat(file_path.value().c_str(), &file_info) != 0) 1.378 + return false; 1.379 + results->is_directory = S_ISDIR(file_info.st_mode); 1.380 + results->size = file_info.st_size; 1.381 + return true; 1.382 +} 1.383 + 1.384 +FILE* OpenFile(const std::string& filename, const char* mode) { 1.385 + return OpenFile(FilePath(filename), mode); 1.386 +} 1.387 + 1.388 +FILE* OpenFile(const FilePath& filename, const char* mode) { 1.389 + return fopen(filename.value().c_str(), mode); 1.390 +} 1.391 + 1.392 +int ReadFile(const FilePath& filename, char* data, int size) { 1.393 + int fd = open(filename.value().c_str(), O_RDONLY); 1.394 + if (fd < 0) 1.395 + return -1; 1.396 + 1.397 + int ret_value = HANDLE_EINTR(read(fd, data, size)); 1.398 + HANDLE_EINTR(close(fd)); 1.399 + return ret_value; 1.400 +} 1.401 + 1.402 +int WriteFile(const FilePath& filename, const char* data, int size) { 1.403 + int fd = creat(filename.value().c_str(), 0666); 1.404 + if (fd < 0) 1.405 + return -1; 1.406 + 1.407 + // Allow for partial writes 1.408 + ssize_t bytes_written_total = 0; 1.409 + do { 1.410 + ssize_t bytes_written_partial = 1.411 + HANDLE_EINTR(write(fd, data + bytes_written_total, 1.412 + size - bytes_written_total)); 1.413 + if (bytes_written_partial < 0) { 1.414 + HANDLE_EINTR(close(fd)); 1.415 + return -1; 1.416 + } 1.417 + bytes_written_total += bytes_written_partial; 1.418 + } while (bytes_written_total < size); 1.419 + 1.420 + HANDLE_EINTR(close(fd)); 1.421 + return bytes_written_total; 1.422 +} 1.423 + 1.424 +// Gets the current working directory for the process. 1.425 +bool GetCurrentDirectory(FilePath* dir) { 1.426 + char system_buffer[PATH_MAX] = ""; 1.427 + if (!getcwd(system_buffer, sizeof(system_buffer))) { 1.428 + NOTREACHED(); 1.429 + return false; 1.430 + } 1.431 + *dir = FilePath(system_buffer); 1.432 + return true; 1.433 +} 1.434 + 1.435 +// Sets the current working directory for the process. 1.436 +bool SetCurrentDirectory(const FilePath& path) { 1.437 + int ret = chdir(path.value().c_str()); 1.438 + return !ret; 1.439 +} 1.440 + 1.441 +#if !defined(OS_MACOSX) 1.442 +bool GetTempDir(FilePath* path) { 1.443 + const char* tmp = getenv("TMPDIR"); 1.444 + if (tmp) 1.445 + *path = FilePath(tmp); 1.446 + else 1.447 + *path = FilePath("/tmp"); 1.448 + return true; 1.449 +} 1.450 + 1.451 +bool GetShmemTempDir(FilePath* path) { 1.452 +#if defined(OS_LINUX) && !defined(ANDROID) 1.453 + *path = FilePath("/dev/shm"); 1.454 + return true; 1.455 +#else 1.456 + return GetTempDir(path); 1.457 +#endif 1.458 +} 1.459 + 1.460 +bool CopyFile(const FilePath& from_path, const FilePath& to_path) { 1.461 + int infile = open(from_path.value().c_str(), O_RDONLY); 1.462 + if (infile < 0) 1.463 + return false; 1.464 + 1.465 + int outfile = creat(to_path.value().c_str(), 0666); 1.466 + if (outfile < 0) { 1.467 + close(infile); 1.468 + return false; 1.469 + } 1.470 + 1.471 + const size_t kBufferSize = 32768; 1.472 + std::vector<char> buffer(kBufferSize); 1.473 + bool result = true; 1.474 + 1.475 + while (result) { 1.476 + ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size())); 1.477 + if (bytes_read < 0) { 1.478 + result = false; 1.479 + break; 1.480 + } 1.481 + if (bytes_read == 0) 1.482 + break; 1.483 + // Allow for partial writes 1.484 + ssize_t bytes_written_per_read = 0; 1.485 + do { 1.486 + ssize_t bytes_written_partial = HANDLE_EINTR(write( 1.487 + outfile, 1.488 + &buffer[bytes_written_per_read], 1.489 + bytes_read - bytes_written_per_read)); 1.490 + if (bytes_written_partial < 0) { 1.491 + result = false; 1.492 + break; 1.493 + } 1.494 + bytes_written_per_read += bytes_written_partial; 1.495 + } while (bytes_written_per_read < bytes_read); 1.496 + } 1.497 + 1.498 + if (HANDLE_EINTR(close(infile)) < 0) 1.499 + result = false; 1.500 + if (HANDLE_EINTR(close(outfile)) < 0) 1.501 + result = false; 1.502 + 1.503 + return result; 1.504 +} 1.505 +#endif // !defined(OS_MACOSX) 1.506 + 1.507 +} // namespace file_util