mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
214 lines
6.4 KiB
C++
214 lines
6.4 KiB
C++
// Copyright 2026 Google LLC
|
|
//
|
|
// Licensed 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
|
|
//
|
|
// https://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.
|
|
|
|
#include "sharing/linux/app/native_file_logging.h"
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/file.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include <cstdio>
|
|
#include <system_error>
|
|
#include <utility>
|
|
|
|
#include "absl/log/globals.h"
|
|
#include "absl/log/initialize.h"
|
|
#include "absl/log/log_sink_registry.h"
|
|
#include "absl/strings/string_view.h"
|
|
#include "sharing/linux/platform/platform_util.h"
|
|
|
|
namespace nearby::sharing::linux {
|
|
namespace {
|
|
|
|
constexpr char kLogFileName[] = "quickshare.log";
|
|
constexpr char kLockFileName[] = ".quickshare.log.lock";
|
|
|
|
bool WriteAll(int fd, const char* data, size_t size) {
|
|
while (size > 0) {
|
|
const ssize_t written = write(fd, data, size);
|
|
if (written < 0) {
|
|
if (errno == EINTR) {
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
data += written;
|
|
size -= static_cast<size_t>(written);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void WriteToStderr(absl::string_view message) {
|
|
static_cast<void>(WriteAll(STDERR_FILENO, message.data(), message.size()));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
std::unique_ptr<NativeFileLogSink> NativeFileLogSink::Create(
|
|
std::filesystem::path log_directory, size_t max_file_size, int file_count) {
|
|
if (max_file_size == 0 || file_count < 1) {
|
|
return nullptr;
|
|
}
|
|
|
|
std::error_code error;
|
|
std::filesystem::create_directories(log_directory, error);
|
|
if (error) {
|
|
return nullptr;
|
|
}
|
|
std::filesystem::permissions(log_directory, std::filesystem::perms::owner_all,
|
|
std::filesystem::perm_options::replace, error);
|
|
if (error) {
|
|
return nullptr;
|
|
}
|
|
|
|
const std::filesystem::path lock_path = log_directory / kLockFileName;
|
|
const int lock_fd =
|
|
open(lock_path.c_str(), O_CREAT | O_RDWR | O_CLOEXEC | O_NOFOLLOW, 0600);
|
|
if (lock_fd < 0) {
|
|
return nullptr;
|
|
}
|
|
if (fchmod(lock_fd, 0600) != 0) {
|
|
close(lock_fd);
|
|
return nullptr;
|
|
}
|
|
|
|
const std::filesystem::path log_path = log_directory / kLogFileName;
|
|
const int log_fd =
|
|
open(log_path.c_str(),
|
|
O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW, 0600);
|
|
if (log_fd < 0 || fchmod(log_fd, 0600) != 0) {
|
|
if (log_fd >= 0) {
|
|
close(log_fd);
|
|
}
|
|
close(lock_fd);
|
|
return nullptr;
|
|
}
|
|
close(log_fd);
|
|
|
|
return std::unique_ptr<NativeFileLogSink>(new NativeFileLogSink(
|
|
std::move(log_directory), lock_fd, max_file_size, file_count));
|
|
}
|
|
|
|
NativeFileLogSink::NativeFileLogSink(std::filesystem::path log_directory,
|
|
int lock_fd, size_t max_file_size,
|
|
int file_count)
|
|
: log_path_(std::move(log_directory) / kLogFileName),
|
|
lock_fd_(lock_fd),
|
|
max_file_size_(max_file_size),
|
|
file_count_(file_count) {}
|
|
|
|
NativeFileLogSink::~NativeFileLogSink() {
|
|
close(lock_fd_);
|
|
}
|
|
|
|
void NativeFileLogSink::Send(const absl::LogEntry& entry) {
|
|
const absl::string_view message =
|
|
entry.text_message_with_prefix_and_newline();
|
|
const bool flush = entry.log_severity() >= absl::LogSeverity::kError;
|
|
|
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
if (flock(lock_fd_, LOCK_EX) != 0) {
|
|
WriteFallback(message.data(), message.size());
|
|
return;
|
|
}
|
|
|
|
const bool success = RotateIfNeeded(message.size()) &&
|
|
WriteRecord(message.data(), message.size(), flush);
|
|
static_cast<void>(flock(lock_fd_, LOCK_UN));
|
|
if (!success) {
|
|
WriteFallback(message.data(), message.size());
|
|
}
|
|
}
|
|
|
|
bool NativeFileLogSink::RotateIfNeeded(size_t incoming_size) {
|
|
struct stat status{};
|
|
if (stat(log_path_.c_str(), &status) != 0) {
|
|
return errno == ENOENT;
|
|
}
|
|
const size_t current_size =
|
|
status.st_size > 0 ? static_cast<size_t>(status.st_size) : 0;
|
|
if (current_size == 0 || (incoming_size <= max_file_size_ &&
|
|
current_size <= max_file_size_ - incoming_size)) {
|
|
return true;
|
|
}
|
|
|
|
for (int index = file_count_ - 1; index >= 1; --index) {
|
|
const std::filesystem::path destination =
|
|
log_path_.string() + "." + std::to_string(index);
|
|
const std::filesystem::path source =
|
|
index == 1 ? log_path_
|
|
: std::filesystem::path(log_path_.string() + "." +
|
|
std::to_string(index - 1));
|
|
if (rename(source.c_str(), destination.c_str()) != 0 && errno != ENOENT) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool NativeFileLogSink::WriteRecord(const char* data, size_t size, bool flush) {
|
|
const int fd =
|
|
open(log_path_.c_str(),
|
|
O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW, 0600);
|
|
if (fd < 0) {
|
|
return false;
|
|
}
|
|
|
|
bool success = fchmod(fd, 0600) == 0 && WriteAll(fd, data, size);
|
|
if (success && flush) {
|
|
success = fsync(fd) == 0;
|
|
}
|
|
if (close(fd) != 0) {
|
|
success = false;
|
|
}
|
|
return success;
|
|
}
|
|
|
|
void NativeFileLogSink::WriteFallback(const char* data, size_t size) {
|
|
WriteToStderr(absl::string_view(data, size));
|
|
}
|
|
|
|
std::unique_ptr<NativeFileLogging> NativeFileLogging::Initialize() {
|
|
std::unique_ptr<NativeFileLogSink> sink =
|
|
NativeFileLogSink::Create(internal::GetQuickShareLogPath().ToString());
|
|
absl::InitializeLog();
|
|
if (sink == nullptr) {
|
|
WriteToStderr(
|
|
"QuickShare: unable to initialize file logging; using "
|
|
"stderr.\n");
|
|
return nullptr;
|
|
}
|
|
|
|
absl::AddLogSink(sink.get());
|
|
const absl::LogSeverityAtLeast previous_threshold = absl::StderrThreshold();
|
|
absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfinity);
|
|
return std::unique_ptr<NativeFileLogging>(
|
|
new NativeFileLogging(std::move(sink), previous_threshold));
|
|
}
|
|
|
|
NativeFileLogging::NativeFileLogging(
|
|
std::unique_ptr<NativeFileLogSink> sink,
|
|
absl::LogSeverityAtLeast previous_stderr_threshold)
|
|
: sink_(std::move(sink)),
|
|
previous_stderr_threshold_(previous_stderr_threshold) {}
|
|
|
|
NativeFileLogging::~NativeFileLogging() {
|
|
absl::SetStderrThreshold(previous_stderr_threshold_);
|
|
absl::RemoveLogSink(sink_.get());
|
|
}
|
|
|
|
} // namespace nearby::sharing::linux
|