Zonr Chang | 4f94c52 | 2012-04-05 15:09:28 +0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2012, The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "OutputFile.h" |
| 18 | |
| 19 | #include <cstdlib> |
| 20 | |
| 21 | #include <llvm/Support/raw_ostream.h> |
| 22 | |
| 23 | #include "DebugHelper.h" |
| 24 | |
| 25 | using namespace bcc; |
| 26 | |
| 27 | OutputFile *OutputFile::CreateTemporary(const std::string &pFileTemplate, |
| 28 | unsigned pFlags) { |
| 29 | char *tmp_filename = NULL; |
| 30 | int tmp_fd; |
| 31 | OutputFile *result = NULL; |
| 32 | |
| 33 | // Allocate memory to hold the generated unique temporary filename. |
| 34 | tmp_filename = |
| 35 | new (std::nothrow) char [ pFileTemplate.length() + /* .XXXXXX */7 + 1 ]; |
| 36 | if (tmp_filename == NULL) { |
| 37 | ALOGE("Out of memory when allocates memory for filename %s in " |
| 38 | "OutputFile::CreateTemporary()!", pFileTemplate.c_str()); |
| 39 | return NULL; |
| 40 | } |
| 41 | |
| 42 | // Construct filename template for mkstemp(). |
| 43 | if (pFileTemplate.length() > 0) |
| 44 | ::memcpy(tmp_filename, pFileTemplate.c_str(), pFileTemplate.length()); |
| 45 | ::strncpy(tmp_filename + pFileTemplate.length(), ".XXXXXX", 7); |
| 46 | |
| 47 | // POSIX mkstemp() never returns EINTR. |
| 48 | tmp_fd = ::mkstemp(tmp_filename); |
| 49 | if (tmp_fd < 0) { |
| 50 | llvm::error_code err(errno, llvm::posix_category()); |
| 51 | ALOGE("Failed to create temporary file using mkstemp() for %s! (%s)", |
| 52 | tmp_filename, err.message().c_str()); |
| 53 | delete [] tmp_filename; |
| 54 | return NULL; |
| 55 | } |
| 56 | |
| 57 | // Create result OutputFile. |
| 58 | result = new (std::nothrow) OutputFile(tmp_filename, pFlags); |
| 59 | if (result == NULL) { |
| 60 | ALOGE("Out of memory when creates OutputFile for %s!", tmp_filename); |
| 61 | // Fall through to the clean-up codes. |
| 62 | } else { |
| 63 | if (result->hasError()) { |
| 64 | ALOGE("Failed to open temporary output file %s! (%s)", |
| 65 | result->getName().c_str(), result->getErrorMessage().c_str()); |
| 66 | delete result; |
| 67 | result = NULL; |
| 68 | // Fall through to the clean-up codes. |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | // Clean up. |
| 73 | delete [] tmp_filename; |
| 74 | ::close(tmp_fd); |
| 75 | |
| 76 | return result; |
| 77 | } |
| 78 | |
| 79 | OutputFile::OutputFile(const std::string &pFilename, unsigned pFlags) |
| 80 | : super(pFilename, pFlags) { } |
| 81 | |
| 82 | ssize_t OutputFile::write(const void *pBuf, size_t count) { |
| 83 | if ((mFD < 0) || hasError()) { |
| 84 | return -1; |
| 85 | } |
| 86 | |
| 87 | if ((count <= 0) || (pBuf == NULL)) { |
| 88 | // Keep safe and issue a warning. |
Shih-wei Liao | d14994d | 2012-06-05 03:51:33 -0700 | [diff] [blame^] | 89 | ALOGW("OutputFile::write: count = %zu, buffer = %p", count, pBuf); |
Zonr Chang | 4f94c52 | 2012-04-05 15:09:28 +0800 | [diff] [blame] | 90 | return 0; |
| 91 | } |
| 92 | |
| 93 | while (count > 0) { |
| 94 | ssize_t write_size = ::write(mFD, pBuf, count); |
| 95 | |
| 96 | if (write_size > 0) { |
| 97 | return write_size; |
| 98 | } else if ((errno == EAGAIN) || (errno == EINTR)) { |
| 99 | // If the errno is EAGAIN or EINTR, then we try to write again. |
| 100 | // |
| 101 | // Fall-through |
| 102 | } else { |
| 103 | detectError(); |
| 104 | return -1; |
| 105 | } |
| 106 | } |
| 107 | // unreachable |
| 108 | return 0; |
| 109 | } |
| 110 | |
| 111 | void OutputFile::truncate() { |
| 112 | if (mFD < 0) { |
| 113 | return; |
| 114 | } |
| 115 | |
| 116 | do { |
| 117 | if (::ftruncate(mFD, 0) == 0) { |
| 118 | return; |
| 119 | } |
| 120 | } while (errno == EINTR); |
| 121 | detectError(); |
| 122 | |
| 123 | return; |
| 124 | } |
| 125 | |
| 126 | llvm::raw_fd_ostream *OutputFile::dup() { |
| 127 | int newfd; |
| 128 | |
| 129 | do { |
| 130 | newfd = ::dup(mFD); |
| 131 | if (newfd < 0) { |
| 132 | if (errno != EINTR) { |
| 133 | detectError(); |
| 134 | return NULL; |
| 135 | } |
| 136 | // EINTR |
| 137 | continue; |
| 138 | } |
| 139 | // dup() returns ok. |
| 140 | break; |
| 141 | } while (true); |
| 142 | |
| 143 | llvm::raw_fd_ostream *result = |
| 144 | new (std::nothrow) llvm::raw_fd_ostream(newfd, /* shouldClose */true); |
| 145 | |
| 146 | if (result == NULL) { |
| 147 | mError.assign(llvm::errc::not_enough_memory, llvm::system_category()); |
| 148 | } |
| 149 | |
| 150 | return result; |
| 151 | } |