blob: d48499a0a402ef6461a5bca8c58b68a3562ffc4f [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// Date: Thu Oct 28 15:27:05 2010
#include <fcntl.h> // open
#include <unistd.h> // close
#include <stdio.h> // snprintf, vdprintf
#include <stdlib.h> // mkstemp
#include <string.h> // strlen
#include <stdarg.h> // va_list
#include <errno.h> // errno
#include <new> // placement new
#include "temp_file.h" // TempFile
// Initializing array. Needs to be macro.
#define BASE_FILES_TEMP_FILE_PATTERN "temp_file_XXXXXX";
namespace butil {
TempFile::TempFile() : _ever_opened(0) {
char temp_name[] = BASE_FILES_TEMP_FILE_PATTERN;
_fd = mkstemp(temp_name);
if (_fd >= 0) {
_ever_opened = 1;
snprintf(_fname, sizeof(_fname), "%s", temp_name);
} else {
*_fname = '\0';
}
}
TempFile::TempFile(const char* ext) {
if (NULL == ext || '\0' == *ext) {
new (this) TempFile();
return;
}
*_fname = '\0';
_fd = -1;
_ever_opened = 0;
// Make a temp file to occupy the filename without ext.
char temp_name[] = BASE_FILES_TEMP_FILE_PATTERN;
const int tmp_fd = mkstemp(temp_name);
if (tmp_fd < 0) {
return;
}
// Open the temp_file_XXXXXX.ext
snprintf(_fname, sizeof(_fname), "%s.%s", temp_name, ext);
_fd = open(_fname, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0600);
if (_fd < 0) {
*_fname = '\0';
} else {
_ever_opened = 1;
}
// Close and remove temp_file_XXXXXX anyway.
close(tmp_fd);
unlink(temp_name);
}
int TempFile::_reopen_if_necessary() {
if (_fd < 0) {
_fd = open(_fname, O_CREAT | O_WRONLY | O_TRUNC, 0600);
}
return _fd;
}
TempFile::~TempFile() {
if (_fd >= 0) {
close(_fd);
_fd = -1;
}
if (_ever_opened) {
// Only remove temp file when _fd >= 0, otherwise we may
// remove another temporary file (occupied the same name)
unlink(_fname);
}
}
int TempFile::save(const char *content) {
return save_bin(content, strlen(content));
}
int TempFile::save_format(const char *fmt, ...) {
if (_reopen_if_necessary() < 0) {
return -1;
}
va_list ap;
va_start(ap, fmt);
const int rc = vdprintf(_fd, fmt, ap);
va_end(ap);
close(_fd);
_fd = -1;
// TODO: is this right?
return (rc < 0 ? -1 : 0);
}
// Write until all buffer was written or an error except EINTR.
// Returns:
// -1 error happened, errno is set
// count all written
static ssize_t temp_file_write_all(int fd, const void *buf, size_t count) {
size_t off = 0;
for (;;) {
ssize_t nw = write(fd, (char*)buf + off, count - off);
if (nw == (ssize_t)(count - off)) { // including count==0
return count;
}
if (nw >= 0) {
off += nw;
} else if (errno != EINTR) {
return -1;
}
}
}
int TempFile::save_bin(const void *buf, size_t count) {
if (_reopen_if_necessary() < 0) {
return -1;
}
const ssize_t len = temp_file_write_all(_fd, buf, count);
close(_fd);
_fd = -1;
if (len < 0) {
return -1;
} else if ((size_t)len != count) {
errno = ENOSPC;
return -1;
}
return 0;
}
} // namespace butil