Derive agi::acs exceptions from agi::FileSystemError and friends rather than having two sets of errors for the same thing

Originally committed to SVN as r6278.
This commit is contained in:
Thomas Goyne 2012-01-12 22:31:54 +00:00
parent 7031ba807b
commit 7dd6cfe37d
18 changed files with 94 additions and 117 deletions

View File

@ -34,7 +34,6 @@
#include "libaegisub/hotkey.h"
#include "libaegisub/access.h"
#include "libaegisub/cajun/writer.h"
#include "libaegisub/exception.h"
#include "libaegisub/io.h"

View File

@ -25,7 +25,6 @@
#include <sstream>
#endif
#include "libaegisub/access.h"
#include "libaegisub/io.h"
#include "libaegisub/json.h"
#include "libaegisub/log.h"
@ -59,7 +58,7 @@ json::UnknownElement file(const std::string &file, const std::string &default_co
try {
return parse(io::Open(file));
}
catch (const acs::AcsNotFound&) {
catch (FileNotFoundError const&) {
// Not an error
return parse(new std::istringstream(default_config));
}
@ -68,7 +67,7 @@ json::UnknownElement file(const std::string &file, const std::string &default_co
return parse(new std::istringstream(default_config));
}
catch (agi::Exception& e) {
LOG_E("json/file") << "Unexpted error when reading config file " << file << ": " << e.GetMessage();
LOG_E("json/file") << "Unexpected error when reading config file " << file << ": " << e.GetMessage();
return parse(new std::istringstream(default_config));
}
}

View File

@ -22,7 +22,6 @@
#include "libaegisub/cajun/writer.h"
#include "libaegisub/access.h"
#include "libaegisub/io.h"
#include "libaegisub/json.h"
#include "libaegisub/log.h"

View File

@ -34,7 +34,6 @@
#include "libaegisub/cajun/writer.h"
#include "libaegisub/cajun/elements.h"
#include "libaegisub/access.h"
#include "libaegisub/io.h"
#include "libaegisub/log.h"
#include "libaegisub/option_value.h"
@ -101,7 +100,7 @@ void Options::ConfigUser() {
try {
stream.reset(agi::io::Open(config_file));
} catch (const acs::AcsNotFound&) {
} catch (const FileNotFoundError&) {
return;
}

View File

@ -23,16 +23,12 @@
namespace agi {
namespace acs {
DEFINE_BASE_EXCEPTION_NOINNER(AcsError, Exception)
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsFatal, AcsError, "acs/fatal")
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsNotFound, AcsError, "acs/notfound")
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsNotAFile, AcsError, "acs/file")
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsNotADirectory, AcsError, "acs/directory")
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsAccess, AcsError, "acs/access")
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsRead, AcsAccess, "acs/access/read")
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsWrite, AcsAccess, "acs/access/write")
DEFINE_SIMPLE_EXCEPTION_NOINNER(Fatal, FileSystemError, "filesystem/fatal");
DEFINE_SIMPLE_EXCEPTION_NOINNER(NotAFile, FileSystemError, "filesystem/not_a_file")
DEFINE_SIMPLE_EXCEPTION_NOINNER(NotADirectory, FileSystemError, "filesystem/not_a_directory")
DEFINE_SIMPLE_EXCEPTION_NOINNER(Read, FileNotAccessibleError, "filesystem/not_accessible/read_permission")
DEFINE_SIMPLE_EXCEPTION_NOINNER(Write, FileNotAccessibleError, "filesystem/not_accessible/write_permission")
enum Type {
FileRead,
@ -41,7 +37,6 @@ enum Type {
DirWrite
};
void Check(const std::string &file, acs::Type);
void CheckFileRead(const std::string &file);
@ -50,6 +45,5 @@ void CheckDirRead(const std::string &dir);
void CheckFileWrite(const std::string &file);
void CheckDirWrite(const std::string &dir);
} // namespace axs
} // namespace agi

View File

@ -25,7 +25,6 @@
#include <algorithm>
#endif // LAGI_PRE
#include <libaegisub/access.h>
#include <libaegisub/types.h>
namespace agi {

View File

@ -61,15 +61,15 @@ void Check(const std::string &file, acs::Type type) {
if (file_status != 0) {
switch (errno) {
case ENOENT:
throw AcsNotFound("File or path not found.");
throw FileNotFoundError("File or path not found.");
break;
case EACCES:
throw AcsAccess("Access Denied to file, path or path component.");
throw Read("Access Denied to file, path or path component.");
break;
case EIO:
throw AcsFatal("Fatal I/O error occurred.");
throw Fatal("Fatal I/O error occurred.");
break;
}
}
@ -78,13 +78,13 @@ void Check(const std::string &file, acs::Type type) {
case FileRead:
case FileWrite:
if ((file_stat.st_mode & S_IFREG) == 0)
throw AcsNotAFile("Not a file.");
throw NotAFile("Not a file.");
break;
case DirRead:
case DirWrite:
if ((file_stat.st_mode & S_IFDIR) == 0)
throw AcsNotADirectory("Not a directory.");
throw NotADirectory("Not a directory.");
break;
}
@ -93,14 +93,14 @@ void Check(const std::string &file, acs::Type type) {
case FileRead:
file_status = access(file.c_str(), R_OK);
if (file_status != 0)
throw AcsRead("File or directory is not readable.");
throw Read("File or directory is not readable.");
break;
case DirWrite:
case FileWrite:
file_status = access(file.c_str(), W_OK);
if (file_status != 0)
throw AcsWrite("File or directory is not writable.");
throw Write("File or directory is not writable.");
break;
}
}

View File

@ -25,11 +25,30 @@
#include <fstream>
#endif
#include <libaegisub/access.h>
#include <libaegisub/charset_conv_win.h>
#include <libaegisub/log.h>
#include <libaegisub/util.h>
#include <libaegisub/util_win.h>
namespace {
bool check_permission(bool is_read, SECURITY_DESCRIPTOR *sd, HANDLE client_token) {
DWORD access_check = is_read ? FILE_READ_DATA : FILE_APPEND_DATA | FILE_WRITE_DATA;
GENERIC_MAPPING generic_mapping;
MapGenericMask(&access_check, &generic_mapping);
PRIVILEGE_SET priv_set;
DWORD priv_set_size = sizeof(PRIVILEGE_SET);
DWORD access;
BOOL access_ok;
if(!AccessCheck(sd, client_token, access_check, &generic_mapping, &priv_set, &priv_set_size, &access, &access_ok))
LOG_W("acs/check") << "AccessCheck failed: " << agi::util::ErrorString(GetLastError());
return !!access;
}
}
namespace agi {
namespace acs {
@ -63,13 +82,13 @@ void Check(const std::string &file, acs::Type type) {
switch (GetLastError()) {
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
throw AcsNotFound("File or path not found.");
throw FileNotFoundError(file);
case ERROR_ACCESS_DENIED:
throw AcsAccess("Access denied to file or path component");
throw Read("Access denied to file or path component");
default:
throw AcsFatal("Fatal I/O error occurred.");
throw Fatal("Fatal I/O error occurred.");
}
}
@ -77,12 +96,12 @@ void Check(const std::string &file, acs::Type type) {
case FileRead:
case FileWrite:
if ((file_attr & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
throw AcsNotAFile("Not a file");
throw NotAFile(file + " is not a file");
break;
case DirRead:
case DirWrite:
if ((file_attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY)
throw AcsNotADirectory("Not a directory");
throw NotADirectory(file + " is not a directory");
break;
}
@ -103,32 +122,10 @@ void Check(const std::string &file, acs::Type type) {
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &client_token))
LOG_W("acs/check") << "OpenThreadToken failed: " << util::ErrorString(GetLastError());
DWORD access_check;
switch (type) {
case DirRead:
case FileRead:
access_check = FILE_READ_DATA;
break;
case DirWrite:
case FileWrite:
access_check = FILE_APPEND_DATA | FILE_WRITE_DATA;
break;
default:
LOG_W("acs/check") << "Warning: type not handled";
return;
}
GENERIC_MAPPING generic_mapping;
MapGenericMask(&access_check, &generic_mapping);
PRIVILEGE_SET priv_set;
DWORD priv_set_size = sizeof(PRIVILEGE_SET);
DWORD access;
BOOL access_ok;
if(!AccessCheck(sd, client_token, access_check, &generic_mapping, &priv_set, &priv_set_size, &access, &access_ok))
LOG_W("acs/check") << "AccessCheck failed: " << util::ErrorString(GetLastError());
if (!access)
throw AcsRead("File or directory is not readable");
if (!check_permission(true, sd, client_token))
throw Read("File or directory is not readable");
if ((type == DirWrite || type == FileWrite) && !check_permission(false, sd, client_token))
throw Write("File or directory is not writable");
}
} // namespace Access

View File

@ -26,6 +26,7 @@
#include <fstream>
#endif
#include <libaegisub/access.h>
#include <libaegisub/charset_conv_win.h>
#include "libaegisub/io.h"
#include "libaegisub/log.h"
@ -60,7 +61,7 @@ Save::Save(const std::string& file, bool binary): file_name(file) {
try {
acs::CheckFileWrite(file);
} catch (acs::AcsNotFound&) {
} catch (FileNotFoundError const&) {
// If the file doesn't exist we create a 0 byte file, this so so
// util::Rename will find it, and to let users know something went
// wrong by leaving a 0 byte file.

View File

@ -28,8 +28,9 @@
#include <windows.h>
#endif
#include "libaegisub/types.h"
#include "libaegisub/access.h"
#include "libaegisub/charset_conv_win.h"
#include "libaegisub/types.h"
#include "libaegisub/util.h"
#include "libaegisub/util_win.h"
@ -52,7 +53,7 @@ void Rename(const std::string& from, const std::string& to) {
try {
acs::CheckFileWrite(to);
} catch (acs::AcsNotFound&) {
} catch (FileNotFoundError const&) {
acs::CheckDirWrite(DirName(to));
}

View File

@ -413,10 +413,10 @@ namespace Automation4 {
}
break;
}
catch (agi::acs::AcsNotFound const&) {
catch (agi::FileNotFoundError const&) {
// Not an error so swallow and continue on
}
catch (agi::acs::AcsNotAFile const&) {
catch (agi::acs::NotAFile const&) {
// Not an error so swallow and continue on
}
catch (agi::Exception const& e) {

View File

@ -38,7 +38,6 @@
#include <wx/textctrl.h>
#endif
#include <libaegisub/access.h>
#include <libaegisub/io.h>
#include <libaegisub/log.h>
#include <libaegisub/scoped_ptr.h>
@ -247,7 +246,7 @@ void DialogShiftTimes::SaveHistory(std::vector<std::pair<int, int> > const& shif
file.Get() << history->GetString(i).utf8_str() << std::endl;
file.Get() << new_line.utf8_str() << std::endl;
}
catch (agi::acs::AcsError const& e) {
catch (agi::FileSystemError const& e) {
LOG_E("dialog_shift_times/save_history") << "Cannot save shift times history: " << e.GetChainedMessage();
}
}
@ -265,7 +264,7 @@ void DialogShiftTimes::LoadHistory() {
history->Insert(lagi_wxString(buffer), 0);
}
}
catch (agi::acs::AcsError const& e) {
catch (agi::FileSystemError const& e) {
LOG_E("dialog_shift_times/save_history") << "Cannot load shift times history: " << e.GetChainedMessage();
}
catch (...) {

View File

@ -47,7 +47,6 @@
#include <wx/tokenzr.h>
#endif
#include <libaegisub/access.h>
#include <libaegisub/log.h>
#include "include/aegisub/context.h"
@ -312,7 +311,7 @@ void FrameMain::LoadSubtitles(wxString filename,wxString charset) {
context->ass->Load(filename,charset);
}
catch (agi::acs::AcsNotFound const&) {
catch (agi::FileNotFoundError const&) {
wxMessageBox(filename + " not found.", "Error", wxOK | wxICON_ERROR, NULL);
config::mru->Remove("Subtitle", STD_STR(filename));
return;

View File

@ -73,7 +73,6 @@
#include "video_context.h"
#include <libaegisub/io.h>
#include <libaegisub/access.h>
#include <libaegisub/log.h>
#include <libaegisub/hotkey.h>
#include <libaegisub/scoped_ptr.h>
@ -160,7 +159,7 @@ bool AegisubApp::OnInit() {
// Local config, make ?user mean ?data so all user settings are placed in install dir
StandardPaths::SetPathValue("?user", StandardPaths::DecodePath("?data"));
StandardPaths::SetPathValue("?local", StandardPaths::DecodePath("?data"));
} catch (agi::acs::AcsError const&) {
} catch (agi::FileNotAccessibleError const&) {
// File doesn't exist or we can't read it
// Might be worth displaying an error in the second case
}

View File

@ -46,7 +46,6 @@
#include <wx/msgdlg.h>
#endif
#include <libaegisub/access.h>
#include <libaegisub/keyframe.h>
#include <libaegisub/log.h>
@ -433,7 +432,7 @@ void VideoContext::LoadKeyframes(wxString filename) {
wxMessageBox(err.GetMessage(), "Error opening keyframes file", wxOK | wxICON_ERROR, NULL);
config::mru->Remove("Keyframes", STD_STR(filename));
}
catch (agi::acs::AcsError const&) {
catch (agi::FileSystemError const&) {
wxLogError("Could not open file " + filename);
config::mru->Remove("Keyframes", STD_STR(filename));
}
@ -462,7 +461,7 @@ void VideoContext::LoadTimecodes(wxString filename) {
OnSubtitlesCommit();
TimecodesOpen(ovrFPS);
}
catch (const agi::acs::AcsError&) {
catch (const agi::FileSystemError&) {
wxLogError("Could not open file " + filename);
config::mru->Remove("Timecodes", STD_STR(filename));
}
@ -475,7 +474,7 @@ void VideoContext::SaveTimecodes(wxString filename) {
FPS().Save(STD_STR(filename), IsLoaded() ? GetLength() : -1);
config::mru->Add("Timecodes", STD_STR(filename));
}
catch(const agi::acs::AcsError&) {
catch(const agi::FileSystemError&) {
wxLogError("Could not write to " + filename);
}
}

View File

@ -22,6 +22,7 @@
#include "main.h"
using namespace agi;
using namespace agi::acs;
class lagi_acs : public libagi {
@ -34,76 +35,68 @@ protected:
// Yes, this is a horrifying use of macros, since these are all void static
// methods I couldn't think of a better way to test these without massive code
// duplication.
#define EX_AcsNotFound(func, pass) \
TEST_F(lagi_acs, func##ExAcsNotFound) { \
EXPECT_THROW(func("data/nonexistent"), AcsNotFound); \
#define EX_FileNotFoundError(func, pass) \
TEST_F(lagi_acs, func##ExFileNotFoundError) { \
EXPECT_THROW(func("data/nonexistent"), FileNotFoundError); \
EXPECT_NO_THROW(func(pass)); \
}
#define EX_AcsAccess(func, fail, pass) \
TEST_F(lagi_acs, func##ExAcsAccess) { \
EXPECT_THROW(func(fail), AcsAccess); \
#define EX_Fatal(func, fail, pass) \
TEST_F(lagi_acs, func##ExFatal) { \
EXPECT_THROW(func(fail), Fatal); \
EXPECT_NO_THROW(func(pass)); \
}
#define EX_AcsNotAFile(func, fail, pass) \
TEST_F(lagi_acs, func##ExAcsNotAFile) { \
EXPECT_THROW(func(fail), AcsNotAFile); \
#define EX_NotAFile(func, fail, pass) \
TEST_F(lagi_acs, func##ExNotAFile) { \
EXPECT_THROW(func(fail), NotAFile); \
EXPECT_NO_THROW(func(pass)); \
}
#define EX_AcsNotADirectory(func, fail, pass) \
TEST_F(lagi_acs, func##ExAcsNotADirectory) { \
EXPECT_THROW(func(fail), AcsNotADirectory); \
#define EX_NotADirectory(func, fail, pass) \
TEST_F(lagi_acs, func##ExNotADirectory) { \
EXPECT_THROW(func(fail), NotADirectory); \
EXPECT_NO_THROW(func(pass)); \
}
#define EX_AcsRead(func, fail, pass) \
TEST_F(lagi_acs, func##ExAcsRead) { \
EXPECT_THROW(func(fail), AcsRead); \
#define EX_Read(func, fail, pass) \
TEST_F(lagi_acs, func##ExRead) { \
EXPECT_THROW(func(fail), Read); \
EXPECT_NO_THROW(func(pass)); \
}
#define EX_AcsWrite(func, fail, pass) \
TEST_F(lagi_acs, func##ExAcsWrite) { \
EXPECT_THROW(func(fail), AcsWrite); \
#define EX_Write(func, fail, pass) \
TEST_F(lagi_acs, func##ExWrite) { \
EXPECT_THROW(func(fail), Write); \
EXPECT_NO_THROW(func(pass)); \
}
/*
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsFatal, AcsError, "io/fatal")
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsAccessRead, AcsError, "io/read")
DEFINE_SIMPLE_EXCEPTION_NOINNER(AcsAccessWrite, AcsError, "io/write")
*/
EX_AcsNotFound(CheckFileRead, "data/file")
EX_AcsAccess(CheckFileRead, "data/file_access_denied", "data/file")
EX_AcsNotAFile(CheckFileRead, "data/dir", "data/file")
EX_FileNotFoundError(CheckFileRead, "data/file")
EX_Read(CheckFileRead, "data/file_access_denied", "data/file")
EX_NotAFile(CheckFileRead, "data/dir", "data/file")
TEST_F(lagi_acs, CheckFileRead) {
EXPECT_NO_THROW(CheckFileRead("data/file"));
}
EX_AcsNotFound(CheckFileWrite, "data/file")
EX_AcsAccess(CheckFileWrite, "data/file_access_denied", "data/file")
EX_AcsNotAFile(CheckFileWrite, "data/dir", "data/file")
EX_AcsWrite(CheckFileWrite, "data/file_read_only", "data/file")
EX_FileNotFoundError(CheckFileWrite, "data/file")
EX_Read(CheckFileWrite, "data/file_access_denied", "data/file")
EX_NotAFile(CheckFileWrite, "data/dir", "data/file")
EX_Write(CheckFileWrite, "data/file_read_only", "data/file")
TEST_F(lagi_acs, CheckFileWrite) {
EXPECT_NO_THROW(CheckFileRead("data/file"));
}
EX_AcsNotFound(CheckDirRead, "data/dir")
EX_AcsAccess(CheckDirRead, "data/dir_access_denied", "data/dir")
EX_AcsNotADirectory(CheckDirRead, "data/file", "data/dir")
EX_FileNotFoundError(CheckDirRead, "data/dir")
EX_Read(CheckDirRead, "data/dir_access_denied", "data/dir")
EX_NotADirectory(CheckDirRead, "data/file", "data/dir")
TEST_F(lagi_acs, CheckDirRead) {
EXPECT_NO_THROW(CheckDirRead("data/dir"));
}
EX_AcsNotFound(CheckDirWrite, "data/dir")
EX_AcsAccess(CheckDirWrite, "data/dir_access_denied", "data/dir")
EX_AcsNotADirectory(CheckDirWrite, "data/file", "data/dir")
EX_AcsWrite(CheckDirWrite, "data/dir_read_only", "data/dir")
EX_FileNotFoundError(CheckDirWrite, "data/dir")
EX_Read(CheckDirWrite, "data/dir_access_denied", "data/dir")
EX_NotADirectory(CheckDirWrite, "data/file", "data/dir")
EX_Write(CheckDirWrite, "data/dir_read_only", "data/dir")
TEST_F(lagi_acs, CheckDirWrite) {
EXPECT_NO_THROW(CheckDirWrite("data/dir"));
}

View File

@ -18,7 +18,6 @@
/// @brief agi::keyframe tests
/// @ingroup video_input
#include <libaegisub/access.h>
#include <libaegisub/keyframe.h>
#include <fstream>
@ -42,7 +41,7 @@ TEST(lagi_keyframe, save) {
}
TEST(lagi_keyframe, bad_files) {
EXPECT_THROW(Load(""), agi::acs::AcsError);
EXPECT_THROW(Load(""), agi::FileSystemError);
EXPECT_THROW(Load("data/keyframe/empty.txt"), Error);
EXPECT_THROW(Load("data/keyframe/garbage.txt"), Error);
}

View File

@ -19,6 +19,7 @@
/// @ingroup util
#include <fstream>
#include <libaegisub/access.h>
#include <libaegisub/util.h>
#include "main.h"
@ -62,7 +63,7 @@ TEST_F(lagi_util, UtilRenameNew) {
}
TEST_F(lagi_util, UtilRenameExNotFound) {
EXPECT_THROW(util::Rename("./data/nonexistent", ""), acs::AcsNotFound);
EXPECT_THROW(util::Rename("./data/nonexistent", ""), FileNotFoundError);
}
TEST_F(lagi_util, Utilstr_lower) {
@ -111,7 +112,7 @@ TEST_F(lagi_util, UtilfreespaceDir) {
TEST_F(lagi_util, UtilfreespaceNoAccess) {
std::string path("./data/dir_access_denied");
EXPECT_THROW(util::freespace(path), acs::AcsAccess);
EXPECT_THROW(util::freespace(path), acs::Read);
}
TEST_F(lagi_util, UtilfreespaceInvalid) {