14f94c520f8d699a5973956a1716272146be17128Zonr Chang/* 24f94c520f8d699a5973956a1716272146be17128Zonr Chang * Copyright 2012, The Android Open Source Project 34f94c520f8d699a5973956a1716272146be17128Zonr Chang * 44f94c520f8d699a5973956a1716272146be17128Zonr Chang * Licensed under the Apache License, Version 2.0 (the "License"); 54f94c520f8d699a5973956a1716272146be17128Zonr Chang * you may not use this file except in compliance with the License. 64f94c520f8d699a5973956a1716272146be17128Zonr Chang * You may obtain a copy of the License at 74f94c520f8d699a5973956a1716272146be17128Zonr Chang * 84f94c520f8d699a5973956a1716272146be17128Zonr Chang * http://www.apache.org/licenses/LICENSE-2.0 94f94c520f8d699a5973956a1716272146be17128Zonr Chang * 104f94c520f8d699a5973956a1716272146be17128Zonr Chang * Unless required by applicable law or agreed to in writing, software 114f94c520f8d699a5973956a1716272146be17128Zonr Chang * distributed under the License is distributed on an "AS IS" BASIS, 124f94c520f8d699a5973956a1716272146be17128Zonr Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134f94c520f8d699a5973956a1716272146be17128Zonr Chang * See the License for the specific language governing permissions and 144f94c520f8d699a5973956a1716272146be17128Zonr Chang * limitations under the License. 154f94c520f8d699a5973956a1716272146be17128Zonr Chang */ 164f94c520f8d699a5973956a1716272146be17128Zonr Chang 17c72c4ddfcd79c74f70713da91a69569451b5c19eZonr Chang#include "bcc/Support/OutputFile.h" 184f94c520f8d699a5973956a1716272146be17128Zonr Chang 194f94c520f8d699a5973956a1716272146be17128Zonr Chang#include <cstdlib> 204f94c520f8d699a5973956a1716272146be17128Zonr Chang 214f94c520f8d699a5973956a1716272146be17128Zonr Chang#include <llvm/Support/raw_ostream.h> 224f94c520f8d699a5973956a1716272146be17128Zonr Chang 23ef73a242762bcd8113b9b65ceccbe7d909b5acbcZonr Chang#include "bcc/Support/Log.h" 244f94c520f8d699a5973956a1716272146be17128Zonr Chang 254f94c520f8d699a5973956a1716272146be17128Zonr Changusing namespace bcc; 264f94c520f8d699a5973956a1716272146be17128Zonr Chang 274f94c520f8d699a5973956a1716272146be17128Zonr ChangOutputFile *OutputFile::CreateTemporary(const std::string &pFileTemplate, 284f94c520f8d699a5973956a1716272146be17128Zonr Chang unsigned pFlags) { 294f94c520f8d699a5973956a1716272146be17128Zonr Chang char *tmp_filename = NULL; 304f94c520f8d699a5973956a1716272146be17128Zonr Chang int tmp_fd; 314f94c520f8d699a5973956a1716272146be17128Zonr Chang OutputFile *result = NULL; 324f94c520f8d699a5973956a1716272146be17128Zonr Chang 334f94c520f8d699a5973956a1716272146be17128Zonr Chang // Allocate memory to hold the generated unique temporary filename. 344f94c520f8d699a5973956a1716272146be17128Zonr Chang tmp_filename = 354f94c520f8d699a5973956a1716272146be17128Zonr Chang new (std::nothrow) char [ pFileTemplate.length() + /* .XXXXXX */7 + 1 ]; 364f94c520f8d699a5973956a1716272146be17128Zonr Chang if (tmp_filename == NULL) { 374f94c520f8d699a5973956a1716272146be17128Zonr Chang ALOGE("Out of memory when allocates memory for filename %s in " 384f94c520f8d699a5973956a1716272146be17128Zonr Chang "OutputFile::CreateTemporary()!", pFileTemplate.c_str()); 394f94c520f8d699a5973956a1716272146be17128Zonr Chang return NULL; 404f94c520f8d699a5973956a1716272146be17128Zonr Chang } 414f94c520f8d699a5973956a1716272146be17128Zonr Chang 424f94c520f8d699a5973956a1716272146be17128Zonr Chang // Construct filename template for mkstemp(). 434f94c520f8d699a5973956a1716272146be17128Zonr Chang if (pFileTemplate.length() > 0) 444f94c520f8d699a5973956a1716272146be17128Zonr Chang ::memcpy(tmp_filename, pFileTemplate.c_str(), pFileTemplate.length()); 454f94c520f8d699a5973956a1716272146be17128Zonr Chang ::strncpy(tmp_filename + pFileTemplate.length(), ".XXXXXX", 7); 464f94c520f8d699a5973956a1716272146be17128Zonr Chang 474f94c520f8d699a5973956a1716272146be17128Zonr Chang // POSIX mkstemp() never returns EINTR. 484f94c520f8d699a5973956a1716272146be17128Zonr Chang tmp_fd = ::mkstemp(tmp_filename); 494f94c520f8d699a5973956a1716272146be17128Zonr Chang if (tmp_fd < 0) { 504f94c520f8d699a5973956a1716272146be17128Zonr Chang llvm::error_code err(errno, llvm::posix_category()); 514f94c520f8d699a5973956a1716272146be17128Zonr Chang ALOGE("Failed to create temporary file using mkstemp() for %s! (%s)", 524f94c520f8d699a5973956a1716272146be17128Zonr Chang tmp_filename, err.message().c_str()); 534f94c520f8d699a5973956a1716272146be17128Zonr Chang delete [] tmp_filename; 544f94c520f8d699a5973956a1716272146be17128Zonr Chang return NULL; 554f94c520f8d699a5973956a1716272146be17128Zonr Chang } 564f94c520f8d699a5973956a1716272146be17128Zonr Chang 57c02eae6f35de7dfd92233d591b27c05f15c2a6a1Shih-wei Liao // Create result OutputFile. Temporary file is always truncated. 58c02eae6f35de7dfd92233d591b27c05f15c2a6a1Shih-wei Liao result = new (std::nothrow) OutputFile(tmp_filename, 59c02eae6f35de7dfd92233d591b27c05f15c2a6a1Shih-wei Liao pFlags | FileBase::kTruncate); 604f94c520f8d699a5973956a1716272146be17128Zonr Chang if (result == NULL) { 614f94c520f8d699a5973956a1716272146be17128Zonr Chang ALOGE("Out of memory when creates OutputFile for %s!", tmp_filename); 624f94c520f8d699a5973956a1716272146be17128Zonr Chang // Fall through to the clean-up codes. 634f94c520f8d699a5973956a1716272146be17128Zonr Chang } else { 644f94c520f8d699a5973956a1716272146be17128Zonr Chang if (result->hasError()) { 654f94c520f8d699a5973956a1716272146be17128Zonr Chang ALOGE("Failed to open temporary output file %s! (%s)", 664f94c520f8d699a5973956a1716272146be17128Zonr Chang result->getName().c_str(), result->getErrorMessage().c_str()); 674f94c520f8d699a5973956a1716272146be17128Zonr Chang delete result; 684f94c520f8d699a5973956a1716272146be17128Zonr Chang result = NULL; 694f94c520f8d699a5973956a1716272146be17128Zonr Chang // Fall through to the clean-up codes. 704f94c520f8d699a5973956a1716272146be17128Zonr Chang } 714f94c520f8d699a5973956a1716272146be17128Zonr Chang } 724f94c520f8d699a5973956a1716272146be17128Zonr Chang 734f94c520f8d699a5973956a1716272146be17128Zonr Chang // Clean up. 744f94c520f8d699a5973956a1716272146be17128Zonr Chang delete [] tmp_filename; 754f94c520f8d699a5973956a1716272146be17128Zonr Chang ::close(tmp_fd); 764f94c520f8d699a5973956a1716272146be17128Zonr Chang 774f94c520f8d699a5973956a1716272146be17128Zonr Chang return result; 784f94c520f8d699a5973956a1716272146be17128Zonr Chang} 794f94c520f8d699a5973956a1716272146be17128Zonr Chang 804f94c520f8d699a5973956a1716272146be17128Zonr ChangOutputFile::OutputFile(const std::string &pFilename, unsigned pFlags) 814f94c520f8d699a5973956a1716272146be17128Zonr Chang : super(pFilename, pFlags) { } 824f94c520f8d699a5973956a1716272146be17128Zonr Chang 834f94c520f8d699a5973956a1716272146be17128Zonr Changssize_t OutputFile::write(const void *pBuf, size_t count) { 844f94c520f8d699a5973956a1716272146be17128Zonr Chang if ((mFD < 0) || hasError()) { 854f94c520f8d699a5973956a1716272146be17128Zonr Chang return -1; 864f94c520f8d699a5973956a1716272146be17128Zonr Chang } 874f94c520f8d699a5973956a1716272146be17128Zonr Chang 884f94c520f8d699a5973956a1716272146be17128Zonr Chang if ((count <= 0) || (pBuf == NULL)) { 894f94c520f8d699a5973956a1716272146be17128Zonr Chang // Keep safe and issue a warning. 90d14994d0c77dbd688d6771f5283554aa0ad55808Shih-wei Liao ALOGW("OutputFile::write: count = %zu, buffer = %p", count, pBuf); 914f94c520f8d699a5973956a1716272146be17128Zonr Chang return 0; 924f94c520f8d699a5973956a1716272146be17128Zonr Chang } 934f94c520f8d699a5973956a1716272146be17128Zonr Chang 944f94c520f8d699a5973956a1716272146be17128Zonr Chang while (count > 0) { 954f94c520f8d699a5973956a1716272146be17128Zonr Chang ssize_t write_size = ::write(mFD, pBuf, count); 964f94c520f8d699a5973956a1716272146be17128Zonr Chang 974f94c520f8d699a5973956a1716272146be17128Zonr Chang if (write_size > 0) { 984f94c520f8d699a5973956a1716272146be17128Zonr Chang return write_size; 994f94c520f8d699a5973956a1716272146be17128Zonr Chang } else if ((errno == EAGAIN) || (errno == EINTR)) { 1004f94c520f8d699a5973956a1716272146be17128Zonr Chang // If the errno is EAGAIN or EINTR, then we try to write again. 1014f94c520f8d699a5973956a1716272146be17128Zonr Chang // 1024f94c520f8d699a5973956a1716272146be17128Zonr Chang // Fall-through 1034f94c520f8d699a5973956a1716272146be17128Zonr Chang } else { 1044f94c520f8d699a5973956a1716272146be17128Zonr Chang detectError(); 1054f94c520f8d699a5973956a1716272146be17128Zonr Chang return -1; 1064f94c520f8d699a5973956a1716272146be17128Zonr Chang } 1074f94c520f8d699a5973956a1716272146be17128Zonr Chang } 1084f94c520f8d699a5973956a1716272146be17128Zonr Chang // unreachable 1094f94c520f8d699a5973956a1716272146be17128Zonr Chang return 0; 1104f94c520f8d699a5973956a1716272146be17128Zonr Chang} 1114f94c520f8d699a5973956a1716272146be17128Zonr Chang 1124f94c520f8d699a5973956a1716272146be17128Zonr Changvoid OutputFile::truncate() { 1134f94c520f8d699a5973956a1716272146be17128Zonr Chang if (mFD < 0) { 1144f94c520f8d699a5973956a1716272146be17128Zonr Chang return; 1154f94c520f8d699a5973956a1716272146be17128Zonr Chang } 1164f94c520f8d699a5973956a1716272146be17128Zonr Chang 1174f94c520f8d699a5973956a1716272146be17128Zonr Chang do { 1184f94c520f8d699a5973956a1716272146be17128Zonr Chang if (::ftruncate(mFD, 0) == 0) { 1194f94c520f8d699a5973956a1716272146be17128Zonr Chang return; 1204f94c520f8d699a5973956a1716272146be17128Zonr Chang } 1214f94c520f8d699a5973956a1716272146be17128Zonr Chang } while (errno == EINTR); 1224f94c520f8d699a5973956a1716272146be17128Zonr Chang detectError(); 1234f94c520f8d699a5973956a1716272146be17128Zonr Chang 1244f94c520f8d699a5973956a1716272146be17128Zonr Chang return; 1254f94c520f8d699a5973956a1716272146be17128Zonr Chang} 1264f94c520f8d699a5973956a1716272146be17128Zonr Chang 1274f94c520f8d699a5973956a1716272146be17128Zonr Changllvm::raw_fd_ostream *OutputFile::dup() { 1284f94c520f8d699a5973956a1716272146be17128Zonr Chang int newfd; 1294f94c520f8d699a5973956a1716272146be17128Zonr Chang 1304f94c520f8d699a5973956a1716272146be17128Zonr Chang do { 1314f94c520f8d699a5973956a1716272146be17128Zonr Chang newfd = ::dup(mFD); 1324f94c520f8d699a5973956a1716272146be17128Zonr Chang if (newfd < 0) { 1334f94c520f8d699a5973956a1716272146be17128Zonr Chang if (errno != EINTR) { 1344f94c520f8d699a5973956a1716272146be17128Zonr Chang detectError(); 1354f94c520f8d699a5973956a1716272146be17128Zonr Chang return NULL; 1364f94c520f8d699a5973956a1716272146be17128Zonr Chang } 1374f94c520f8d699a5973956a1716272146be17128Zonr Chang // EINTR 1384f94c520f8d699a5973956a1716272146be17128Zonr Chang continue; 1394f94c520f8d699a5973956a1716272146be17128Zonr Chang } 1404f94c520f8d699a5973956a1716272146be17128Zonr Chang // dup() returns ok. 1414f94c520f8d699a5973956a1716272146be17128Zonr Chang break; 1424f94c520f8d699a5973956a1716272146be17128Zonr Chang } while (true); 1434f94c520f8d699a5973956a1716272146be17128Zonr Chang 1444f94c520f8d699a5973956a1716272146be17128Zonr Chang llvm::raw_fd_ostream *result = 1454f94c520f8d699a5973956a1716272146be17128Zonr Chang new (std::nothrow) llvm::raw_fd_ostream(newfd, /* shouldClose */true); 1464f94c520f8d699a5973956a1716272146be17128Zonr Chang 1474f94c520f8d699a5973956a1716272146be17128Zonr Chang if (result == NULL) { 1484f94c520f8d699a5973956a1716272146be17128Zonr Chang mError.assign(llvm::errc::not_enough_memory, llvm::system_category()); 1494f94c520f8d699a5973956a1716272146be17128Zonr Chang } 1504f94c520f8d699a5973956a1716272146be17128Zonr Chang 1514f94c520f8d699a5973956a1716272146be17128Zonr Chang return result; 1524f94c520f8d699a5973956a1716272146be17128Zonr Chang} 153