mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-06 16:13:26 +00:00
Change the way crash sessions are stored on disk
Changes: * Move classes related to data recovery into app/crash/ directory/namespace * Rename app::Backup to app::crash::Session * Rename app::DataRecovery to app::crash::DataRecovery * Add base::list_files() * Add base::get_current_process_id() and base::is_process_running() * Remove base::TempDir * Save one session for each running process * Remove sessions that are empty when the program starts
This commit is contained in:
parent
e4667149f4
commit
5c6860e7ac
@ -60,7 +60,6 @@ add_library(app-lib
|
||||
app_menus.cpp
|
||||
app_options.cpp
|
||||
app_render.cpp
|
||||
backup.cpp
|
||||
check_update.cpp
|
||||
cmd.cpp
|
||||
cmd/add_cel.cpp
|
||||
@ -226,7 +225,8 @@ add_library(app-lib
|
||||
console.cpp
|
||||
context.cpp
|
||||
context_flags.cpp
|
||||
data_recovery.cpp
|
||||
crash/data_recovery.cpp
|
||||
crash/session.cpp
|
||||
document.cpp
|
||||
document_api.cpp
|
||||
document_exporter.cpp
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "app/commands/commands.h"
|
||||
#include "app/commands/params.h"
|
||||
#include "app/console.h"
|
||||
#include "app/data_recovery.h"
|
||||
#include "app/crash/data_recovery.h"
|
||||
#include "app/document_exporter.h"
|
||||
#include "app/document_location.h"
|
||||
#include "app/document_undo.h"
|
||||
@ -94,7 +94,7 @@ public:
|
||||
CommandsModule m_commands_modules;
|
||||
UIContext m_ui_context;
|
||||
RecentFiles m_recent_files;
|
||||
app::DataRecovery m_recovery;
|
||||
app::crash::DataRecovery m_recovery;
|
||||
scripting::Engine m_scriptingEngine;
|
||||
|
||||
Modules(bool console, bool verbose)
|
||||
|
@ -1,30 +0,0 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/backup.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
Backup::Backup(const std::string& path)
|
||||
: m_path(path)
|
||||
{
|
||||
}
|
||||
|
||||
Backup::~Backup()
|
||||
{
|
||||
}
|
||||
|
||||
bool Backup::hasDataToRestore()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -1,35 +0,0 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_BACKUP_H_INCLUDED
|
||||
#define APP_BACKUP_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
|
||||
// A class to record/restore backup information.
|
||||
class Backup {
|
||||
public:
|
||||
Backup(const std::string& path);
|
||||
~Backup();
|
||||
|
||||
// Returns true if there are items that can be restored.
|
||||
bool hasDataToRestore();
|
||||
|
||||
private:
|
||||
DISABLE_COPYING(Backup);
|
||||
|
||||
std::string m_path;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
113
src/app/crash/data_recovery.cpp
Normal file
113
src/app/crash/data_recovery.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/crash/data_recovery.h"
|
||||
|
||||
#include "app/crash/session.h"
|
||||
#include "app/document.h"
|
||||
#include "app/resource_finder.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/path.h"
|
||||
#include "base/process.h"
|
||||
#include "base/string.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/time.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace app {
|
||||
namespace crash {
|
||||
|
||||
DataRecovery::DataRecovery(doc::Context* context)
|
||||
: m_inProgress(nullptr)
|
||||
, m_context(context)
|
||||
{
|
||||
ResourceFinder rf;
|
||||
rf.includeUserDir(base::join_path("sessions", ".").c_str());
|
||||
std::string sessionsDir = rf.getFirstOrCreateDefault();
|
||||
|
||||
// Existent sessions
|
||||
TRACE("DataRecovery: Listing sessions from '%s'\n", sessionsDir.c_str());
|
||||
for (auto& itemname : base::list_files(sessionsDir)) {
|
||||
std::string itempath = base::join_path(sessionsDir, itemname);
|
||||
if (base::is_directory(itempath)) {
|
||||
TRACE("- Session '%s' ", itempath.c_str());
|
||||
|
||||
SessionPtr session(new Session(itempath));
|
||||
if (!session->isRunning()) {
|
||||
if (!session->isEmpty()) {
|
||||
TRACE("to be loaded\n", itempath.c_str());
|
||||
m_sessions.push_back(session);
|
||||
}
|
||||
else {
|
||||
TRACE("to be deleted\n", itempath.c_str());
|
||||
session->removeFromDisk();
|
||||
}
|
||||
}
|
||||
else
|
||||
TRACE("is running\n", itempath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new session
|
||||
base::pid pid = base::get_current_process_id();
|
||||
std::string newSessionDir;
|
||||
|
||||
do {
|
||||
base::Time time = base::current_time();
|
||||
|
||||
char buf[1024];
|
||||
sprintf(buf, "%04d%02d%02d-%02d%02d%02d-%d",
|
||||
time.year, time.month, time.day,
|
||||
time.hour, time.minute, time.second, pid);
|
||||
|
||||
newSessionDir = base::join_path(sessionsDir, buf);
|
||||
|
||||
if (!base::is_directory(newSessionDir))
|
||||
base::make_directory(newSessionDir);
|
||||
else {
|
||||
base::this_thread::sleep_for(1);
|
||||
newSessionDir.clear();
|
||||
}
|
||||
} while (newSessionDir.empty());
|
||||
|
||||
m_inProgress.reset(new Session(newSessionDir));
|
||||
m_inProgress->create(pid);
|
||||
TRACE("DataRecovery: Session in progress '%s'\n", newSessionDir.c_str());
|
||||
|
||||
m_context->addObserver(this);
|
||||
m_context->documents().addObserver(this);
|
||||
}
|
||||
|
||||
DataRecovery::~DataRecovery()
|
||||
{
|
||||
m_context->documents().removeObserver(this);
|
||||
m_context->removeObserver(this);
|
||||
|
||||
m_inProgress.reset();
|
||||
}
|
||||
|
||||
void DataRecovery::onAddDocument(doc::Document* document)
|
||||
{
|
||||
TRACE("DataRecovery: Observe document %p\n", document);
|
||||
document->addObserver(this);
|
||||
}
|
||||
|
||||
void DataRecovery::onRemoveDocument(doc::Document* document)
|
||||
{
|
||||
TRACE("DataRecovery:: Remove document %p\n", document);
|
||||
document->removeObserver(this);
|
||||
}
|
||||
|
||||
} // namespace crash
|
||||
} // namespace app
|
@ -5,50 +5,49 @@
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_DATA_RECOVERY_H_INCLUDED
|
||||
#define APP_DATA_RECOVERY_H_INCLUDED
|
||||
#ifndef APP_CRASH_DATA_RECOVERY_H_INCLUDED
|
||||
#define APP_CRASH_DATA_RECOVERY_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/crash/session.h"
|
||||
#include "base/disable_copying.h"
|
||||
#include "base/slot.h"
|
||||
#include "doc/context_observer.h"
|
||||
#include "doc/document_observer.h"
|
||||
#include "doc/documents_observer.h"
|
||||
|
||||
namespace base {
|
||||
class TempDir;
|
||||
}
|
||||
#include <vector>
|
||||
|
||||
namespace doc {
|
||||
class Context;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Backup;
|
||||
namespace crash {
|
||||
|
||||
class DataRecovery : public doc::ContextObserver
|
||||
, public doc::DocumentsObserver
|
||||
, public doc::DocumentObserver {
|
||||
public:
|
||||
typedef std::vector<SessionPtr> Sessions;
|
||||
|
||||
DataRecovery(doc::Context* context);
|
||||
~DataRecovery();
|
||||
|
||||
// Returns a backup if there are data to be restored from a
|
||||
// crash. Or null if the program didn't crash in its previous
|
||||
// execution.
|
||||
Backup* getBackup() { return m_backup; }
|
||||
// Returns the list of sessions that can be recovered.
|
||||
const Sessions& sessions() { return m_sessions; }
|
||||
|
||||
private:
|
||||
virtual void onAddDocument(doc::Document* document) override;
|
||||
virtual void onRemoveDocument(doc::Document* document) override;
|
||||
|
||||
base::TempDir* m_tempDir;
|
||||
Backup* m_backup;
|
||||
Sessions m_sessions;
|
||||
SessionPtr m_inProgress;
|
||||
doc::Context* m_context;
|
||||
|
||||
DISABLE_COPYING(DataRecovery);
|
||||
};
|
||||
|
||||
} // namespace crash
|
||||
} // namespace app
|
||||
|
||||
#endif
|
82
src/app/crash/session.cpp
Normal file
82
src/app/crash/session.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/crash/session.h"
|
||||
|
||||
#include "base/fs.h"
|
||||
#include "base/path.h"
|
||||
#include "base/process.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace app {
|
||||
namespace crash {
|
||||
|
||||
Session::Session(const std::string& path)
|
||||
: m_path(path)
|
||||
, m_pid(0)
|
||||
{
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
{
|
||||
}
|
||||
|
||||
bool Session::isRunning()
|
||||
{
|
||||
loadPid();
|
||||
return base::is_process_running(m_pid);
|
||||
}
|
||||
|
||||
bool Session::isEmpty()
|
||||
{
|
||||
return !base::is_file(dataFilename());
|
||||
}
|
||||
|
||||
void Session::create(base::pid pid)
|
||||
{
|
||||
m_pid = pid;
|
||||
|
||||
std::ofstream of(pidFilename());
|
||||
of << m_pid;
|
||||
}
|
||||
|
||||
void Session::removeFromDisk()
|
||||
{
|
||||
base::delete_file(pidFilename());
|
||||
base::remove_directory(m_path);
|
||||
}
|
||||
|
||||
void Session::loadPid()
|
||||
{
|
||||
if (m_pid)
|
||||
return;
|
||||
|
||||
std::string pidfile = pidFilename();
|
||||
if (base::is_file(pidfile)) {
|
||||
std::ifstream pf(pidfile);
|
||||
if (pf)
|
||||
pf >> m_pid;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Session::pidFilename() const
|
||||
{
|
||||
return base::join_path(m_path, "pid");
|
||||
}
|
||||
|
||||
std::string Session::dataFilename() const
|
||||
{
|
||||
return base::join_path(m_path, "data");
|
||||
}
|
||||
|
||||
} // namespace crash
|
||||
} // namespace app
|
52
src/app/crash/session.h
Normal file
52
src/app/crash/session.h
Normal file
@ -0,0 +1,52 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_CRASH_SESSION_H_INCLUDED
|
||||
#define APP_CRASH_SESSION_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
#include "base/process.h"
|
||||
#include "base/shared_ptr.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
namespace app {
|
||||
namespace crash {
|
||||
|
||||
// A class to record/restore session information.
|
||||
class Session {
|
||||
public:
|
||||
Session(const std::string& path);
|
||||
~Session();
|
||||
|
||||
bool isRunning();
|
||||
bool isEmpty();
|
||||
|
||||
void create(base::pid pid);
|
||||
void removeFromDisk();
|
||||
|
||||
private:
|
||||
void loadPid();
|
||||
std::string pidFilename() const;
|
||||
std::string dataFilename() const;
|
||||
|
||||
base::pid m_pid;
|
||||
std::string m_path;
|
||||
std::fstream m_log;
|
||||
std::fstream m_pidFile;
|
||||
|
||||
DISABLE_COPYING(Session);
|
||||
};
|
||||
|
||||
typedef base::SharedPtr<Session> SessionPtr;
|
||||
|
||||
} // namespace crash
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -1,74 +0,0 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/data_recovery.h"
|
||||
|
||||
#include "app/backup.h"
|
||||
#include "app/document.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/path.h"
|
||||
#include "base/temp_dir.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
DataRecovery::DataRecovery(doc::Context* context)
|
||||
: m_tempDir(NULL)
|
||||
, m_backup(NULL)
|
||||
, m_context(context)
|
||||
{
|
||||
// Check if there is already data to recover
|
||||
const std::string existent_data_path = get_config_string("DataRecovery", "Path", "");
|
||||
if (!existent_data_path.empty() &&
|
||||
base::is_directory(existent_data_path)) {
|
||||
// Load the backup data.
|
||||
m_tempDir = new base::TempDir();
|
||||
m_tempDir->attach(existent_data_path);
|
||||
m_backup = new Backup(existent_data_path);
|
||||
}
|
||||
else {
|
||||
// Create a new directory to save the backup information.
|
||||
m_tempDir = new base::TempDir(PACKAGE);
|
||||
m_backup = new Backup(m_tempDir->path());
|
||||
|
||||
set_config_string("DataRecovery", "Path", m_tempDir->path().c_str());
|
||||
flush_config_file();
|
||||
}
|
||||
|
||||
m_context->addObserver(this);
|
||||
m_context->documents().addObserver(this);
|
||||
}
|
||||
|
||||
DataRecovery::~DataRecovery()
|
||||
{
|
||||
m_context->documents().removeObserver(this);
|
||||
m_context->removeObserver(this);
|
||||
|
||||
delete m_backup;
|
||||
|
||||
if (m_tempDir) {
|
||||
delete m_tempDir;
|
||||
set_config_string("DataRecovery", "Path", "");
|
||||
}
|
||||
}
|
||||
|
||||
void DataRecovery::onAddDocument(doc::Document* document)
|
||||
{
|
||||
document->addObserver(this);
|
||||
}
|
||||
|
||||
void DataRecovery::onRemoveDocument(doc::Document* document)
|
||||
{
|
||||
document->removeObserver(this);
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -64,6 +64,7 @@ set(BASE_SOURCES
|
||||
memory_dump.cpp
|
||||
mutex.cpp
|
||||
path.cpp
|
||||
process.cpp
|
||||
program_options.cpp
|
||||
replace_string.cpp
|
||||
serialization.cpp
|
||||
@ -72,7 +73,6 @@ set(BASE_SOURCES
|
||||
split_string.cpp
|
||||
string.cpp
|
||||
system_console.cpp
|
||||
temp_dir.cpp
|
||||
thread.cpp
|
||||
time.cpp
|
||||
trim_string.cpp
|
||||
|
@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace base {
|
||||
|
||||
@ -35,6 +36,8 @@ namespace base {
|
||||
std::string get_temp_path();
|
||||
std::string get_user_docs_folder();
|
||||
|
||||
}
|
||||
std::vector<std::string> list_files(const std::string& path);
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif
|
||||
|
@ -129,4 +129,20 @@ std::string get_user_docs_folder()
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<std::string> list_files(const std::string& path)
|
||||
{
|
||||
WIN32_FIND_DATA fd;
|
||||
std::vector<std::string> files;
|
||||
HANDLE handle = FindFirstFile(base::from_utf8(base::join_path(path, "*")).c_str(), &fd);
|
||||
if (handle) {
|
||||
do {
|
||||
std::string filename = base::to_utf8(fd.cFileName);
|
||||
if (filename != "." && filename != "..")
|
||||
files.push_back(filename);
|
||||
} while (FindNextFile(handle, &fd));
|
||||
FindClose(handle);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
}
|
||||
|
59
src/base/process.cpp
Normal file
59
src/base/process.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
// Aseprite Base Library
|
||||
// Copyright (c) 2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "base/process.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
pid get_current_process_id()
|
||||
{
|
||||
return (pid)GetCurrentProcessId();
|
||||
}
|
||||
|
||||
bool is_process_running(pid pid)
|
||||
{
|
||||
bool running = false;
|
||||
|
||||
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
|
||||
if (handle) {
|
||||
DWORD exitCode = 0;
|
||||
if (GetExitCodeProcess(handle, &exitCode)) {
|
||||
running = (exitCode == STILL_ACTIVE);
|
||||
}
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
return running;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
pid get_current_process_id()
|
||||
{
|
||||
return (pid)getpid();
|
||||
}
|
||||
|
||||
bool is_process_running(pid pid)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace base
|
21
src/base/process.h
Normal file
21
src/base/process.h
Normal file
@ -0,0 +1,21 @@
|
||||
// Aseprite Base Library
|
||||
// Copyright (c) 2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef BASE_PROCESS_H_INCLUDED
|
||||
#define BASE_PROCESS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
namespace base {
|
||||
|
||||
typedef uint32_t pid;
|
||||
|
||||
pid get_current_process_id();
|
||||
|
||||
bool is_process_running(pid pid);
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif
|
@ -1,64 +0,0 @@
|
||||
// Aseprite Base Library
|
||||
// Copyright (c) 2001-2013 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "base/temp_dir.h"
|
||||
|
||||
#include "base/convert_to.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/path.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace base {
|
||||
|
||||
TempDir::TempDir()
|
||||
{
|
||||
}
|
||||
|
||||
TempDir::TempDir(const std::string& appName)
|
||||
{
|
||||
for (int i=(std::rand()%0xffff); ; ++i) {
|
||||
m_path = join_path(get_temp_path(),
|
||||
appName + convert_to<std::string>(i));
|
||||
|
||||
if (!is_directory(m_path)) {
|
||||
make_directory(m_path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TempDir::~TempDir()
|
||||
{
|
||||
remove();
|
||||
}
|
||||
|
||||
void TempDir::remove()
|
||||
{
|
||||
if (!m_path.empty()) {
|
||||
try {
|
||||
remove_directory(m_path);
|
||||
}
|
||||
catch (const std::exception&) {
|
||||
// Ignore exceptions if the directory cannot be removed.
|
||||
}
|
||||
m_path.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void TempDir::attach(const std::string& path)
|
||||
{
|
||||
remove();
|
||||
|
||||
ASSERT(is_directory(path));
|
||||
m_path = path;
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
// Aseprite Base Library
|
||||
// Copyright (c) 2001-2013 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef BASE_TEMP_DIR_H_INCLUDED
|
||||
#define BASE_TEMP_DIR_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace base {
|
||||
|
||||
class TempDir {
|
||||
public:
|
||||
TempDir();
|
||||
TempDir(const std::string& appName);
|
||||
~TempDir();
|
||||
|
||||
void remove();
|
||||
void attach(const std::string& path);
|
||||
const std::string& path() const { return m_path; }
|
||||
|
||||
private:
|
||||
std::string m_path;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user