OutputFile.cpp revision b519fe3f1d780873608f41d69316054e05c7e918
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 "bcc/Support/OutputFile.h" 18 19#include <cstdlib> 20 21#include <llvm/Support/raw_ostream.h> 22 23#include "bcc/Support/Log.h" 24 25using namespace bcc; 26 27OutputFile *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 79OutputFile::OutputFile(const std::string &pFilename, unsigned pFlags) 80 : super(pFilename, pFlags) { } 81 82ssize_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. 89 ALOGW("OutputFile::write: count = %u, buffer = %p", count, pBuf); 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 111void 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 126llvm::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} 152