mirror of
https://github.com/ModOrganizer2/mob.git
synced 2026-07-27 14:07:05 -07:00
comments
moved unsafe flag check to check()
This commit is contained in:
+53
-41
@@ -8,6 +8,8 @@
|
||||
namespace mob::op
|
||||
{
|
||||
|
||||
// most of the functions from the header will check the paths, return early
|
||||
// for dry run, and then forward to these to do the actual work
|
||||
void do_touch(const context& cx, const fs::path& p);
|
||||
void do_create_directories(const context& cx, const fs::path& p);
|
||||
void do_delete_directory(const context& cx, const fs::path& p);
|
||||
@@ -16,24 +18,25 @@ void do_copy_file_to_dir(const context& cx, const fs::path& f, const fs::path& d
|
||||
void do_copy_file_to_file(const context& cx, const fs::path& f, const fs::path& d);
|
||||
void do_remove_readonly(const context& cx, const fs::path& p);
|
||||
void do_rename(const context& cx, const fs::path& src, const fs::path& dest);
|
||||
void check(const context& cx, const fs::path& p);
|
||||
|
||||
// checks whether the path is valid, bails out if not
|
||||
//
|
||||
void check(const context& cx, const fs::path& p, flags f);
|
||||
|
||||
|
||||
void touch(const context& cx, const fs::path& p)
|
||||
void touch(const context& cx, const fs::path& p, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "touching {}", p);
|
||||
check(cx, p);
|
||||
check(cx, p, f);
|
||||
|
||||
if (!conf::dry())
|
||||
do_touch(cx ,p);
|
||||
do_touch(cx, p);
|
||||
}
|
||||
|
||||
void create_directories(const context& cx, const fs::path& p, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "creating dir {}", p);
|
||||
|
||||
if (!is_set(f, unsafe))
|
||||
check(cx, p);
|
||||
check(cx, p, f);
|
||||
|
||||
if (!conf::dry())
|
||||
do_create_directories(cx, p);
|
||||
@@ -42,7 +45,7 @@ void create_directories(const context& cx, const fs::path& p, flags f)
|
||||
void delete_directory(const context& cx, const fs::path& p, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "deleting dir {}", p);
|
||||
check(cx, p);
|
||||
check(cx, p, f);
|
||||
|
||||
if (!fs::exists(p))
|
||||
{
|
||||
@@ -67,7 +70,7 @@ void delete_directory(const context& cx, const fs::path& p, flags f)
|
||||
void delete_file(const context& cx, const fs::path& p, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "deleting file {}", p);
|
||||
check(cx, p);
|
||||
check(cx, p, f);
|
||||
|
||||
if (!fs::exists(p))
|
||||
{
|
||||
@@ -123,17 +126,14 @@ void delete_file_glob(const context& cx, const fs::path& glob, flags f)
|
||||
}
|
||||
}
|
||||
|
||||
void remove_readonly(const context& cx, const fs::path& first)
|
||||
void remove_readonly(const context& cx, const fs::path& dir, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "removing read-only from {}", first);
|
||||
check(cx, first);
|
||||
cx.trace(context::fs, "removing read-only from {}", dir);
|
||||
check(cx, dir, f);
|
||||
|
||||
if (!conf::dry())
|
||||
{
|
||||
if (fs::is_regular_file(first))
|
||||
do_remove_readonly(cx, first);
|
||||
|
||||
for (auto&& p : fs::recursive_directory_iterator(first))
|
||||
for (auto&& p : fs::recursive_directory_iterator(dir))
|
||||
{
|
||||
if (fs::is_regular_file(p))
|
||||
do_remove_readonly(cx, p);
|
||||
@@ -215,10 +215,10 @@ bool is_source_better(
|
||||
return false;
|
||||
}
|
||||
|
||||
void rename(const context& cx, const fs::path& src, const fs::path& dest)
|
||||
void rename(const context& cx, const fs::path& src, const fs::path& dest, flags f)
|
||||
{
|
||||
check(cx, src);
|
||||
check(cx, dest);
|
||||
check(cx, src, f);
|
||||
check(cx, dest, f);
|
||||
|
||||
if (fs::exists(dest))
|
||||
{
|
||||
@@ -227,14 +227,16 @@ void rename(const context& cx, const fs::path& src, const fs::path& dest)
|
||||
}
|
||||
|
||||
cx.trace(context::fs, "renaming {} to {}", src, dest);
|
||||
do_rename(cx, src, dest);
|
||||
|
||||
if (!conf::dry())
|
||||
do_rename(cx, src, dest);
|
||||
}
|
||||
|
||||
void move_to_directory(
|
||||
const context& cx, const fs::path& src, const fs::path& dest_dir)
|
||||
const context& cx, const fs::path& src, const fs::path& dest_dir, flags f)
|
||||
{
|
||||
check(cx, src);
|
||||
check(cx, dest_dir);
|
||||
check(cx, src, f);
|
||||
check(cx, dest_dir, f);
|
||||
|
||||
const auto target = dest_dir / src.filename();
|
||||
|
||||
@@ -246,17 +248,16 @@ void move_to_directory(
|
||||
}
|
||||
|
||||
cx.trace(context::fs, "moving {} to {}", src, target);
|
||||
do_rename(cx, src, target);
|
||||
|
||||
if (!conf::dry())
|
||||
do_rename(cx, src, target);
|
||||
}
|
||||
|
||||
void copy_file_to_dir_if_better(
|
||||
const context& cx, const fs::path& file, const fs::path& dir, flags f)
|
||||
{
|
||||
if ((f & unsafe) == 0)
|
||||
{
|
||||
check(cx, file);
|
||||
check(cx, dir);
|
||||
}
|
||||
check(cx, file, f);
|
||||
check(cx, dir, f);
|
||||
|
||||
if (file.u8string().find(u8"*") != std::string::npos)
|
||||
cx.bail_out(context::fs, "{} contains a glob", file);
|
||||
@@ -297,11 +298,8 @@ void copy_file_to_dir_if_better(
|
||||
void copy_file_to_file_if_better(
|
||||
const context& cx, const fs::path& src, const fs::path& dest, flags f)
|
||||
{
|
||||
if ((f & unsafe) == 0)
|
||||
{
|
||||
check(cx, src);
|
||||
check(cx, dest);
|
||||
}
|
||||
check(cx, src, f);
|
||||
check(cx, dest, f);
|
||||
|
||||
if (src.u8string().find(u8"*") != std::string::npos)
|
||||
cx.bail_out(context::fs, "{} contains a glob", src);
|
||||
@@ -345,6 +343,8 @@ void copy_glob_to_dir_if_better(
|
||||
const context& cx,
|
||||
const fs::path& src_glob, const fs::path& dest_dir, flags f)
|
||||
{
|
||||
check(cx, dest_dir, f);
|
||||
|
||||
const auto file_parent = src_glob.parent_path();
|
||||
const auto wildcard = src_glob.filename().native();
|
||||
|
||||
@@ -400,12 +400,15 @@ void copy_glob_to_dir_if_better(
|
||||
}
|
||||
}
|
||||
|
||||
void swap_files(
|
||||
void replace_file(
|
||||
const context& cx, const fs::path& src, const fs::path& dest,
|
||||
const fs::path& backup, flags)
|
||||
const fs::path& backup, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "swapping {} and {}", src, dest);
|
||||
|
||||
check(cx, src, f);
|
||||
check(cx, dest, f);
|
||||
|
||||
if (conf::dry())
|
||||
return;
|
||||
|
||||
@@ -483,11 +486,14 @@ void write_text_file(
|
||||
const context& cx, encodings e, const fs::path& p,
|
||||
std::string_view utf8, flags f)
|
||||
{
|
||||
check(cx, p);
|
||||
|
||||
const std::string bytes = utf8_to_bytes(e, utf8);
|
||||
cx.trace(context::fs, "writing {} bytes to {}", bytes.size(), p);
|
||||
|
||||
check(cx, p, f);
|
||||
|
||||
if (conf::dry())
|
||||
return;
|
||||
|
||||
{
|
||||
std::ofstream out(p, std::ios::binary);
|
||||
out.write(bytes.data(), static_cast<std::streamsize>(bytes.size()));
|
||||
@@ -513,9 +519,10 @@ void write_text_file(
|
||||
void archive_from_glob(
|
||||
const context& cx,
|
||||
const fs::path& src_glob, const fs::path& dest_file,
|
||||
const std::vector<std::string>& ignore)
|
||||
const std::vector<std::string>& ignore, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "archiving {} into {}", src_glob, dest_file);
|
||||
check(cx, dest_file, f);
|
||||
|
||||
if (conf::dry())
|
||||
return;
|
||||
@@ -526,8 +533,10 @@ void archive_from_glob(
|
||||
void archive_from_files(
|
||||
const context& cx,
|
||||
const std::vector<fs::path>& files, const fs::path& files_root,
|
||||
const fs::path& dest_file)
|
||||
const fs::path& dest_file, flags f)
|
||||
{
|
||||
check(cx, dest_file, f);
|
||||
|
||||
cx.trace(context::fs,
|
||||
"archiving {} files rooted in {} into {}",
|
||||
files.size(), files_root, dest_file);
|
||||
@@ -652,11 +661,14 @@ void do_rename(const context& cx, const fs::path& src, const fs::path& dest)
|
||||
}
|
||||
}
|
||||
|
||||
void check(const context& cx, const fs::path& p)
|
||||
void check(const context& cx, const fs::path& p, flags f)
|
||||
{
|
||||
if (p.empty())
|
||||
cx.bail_out(context::fs, "path is empty");
|
||||
|
||||
if (is_set(f, unsafe))
|
||||
return;
|
||||
|
||||
auto is_inside = [](auto&& p, auto&& dir)
|
||||
{
|
||||
const std::string s = path_to_utf8(p);
|
||||
|
||||
+87
-16
@@ -7,72 +7,143 @@ namespace mob { class context; }
|
||||
namespace mob::op
|
||||
{
|
||||
|
||||
// filesystem operations, also handle --dry
|
||||
//
|
||||
// for functions that end with _if_better(): the source is considered better
|
||||
// than the destination if:
|
||||
// 1) the destination doesn't exist, or
|
||||
// 2) the size is different, or
|
||||
// 3) the date is newer
|
||||
|
||||
|
||||
// various flags for the operations below, only some of them are used by some
|
||||
// functions
|
||||
//
|
||||
enum flags
|
||||
{
|
||||
noflags = 0x00,
|
||||
|
||||
// the operation is optional, don't bail out if it fails
|
||||
optional = 0x01,
|
||||
|
||||
// used by copy_glob_to_dir_if_better() to decide if files and/or
|
||||
// directories are copied
|
||||
copy_files = 0x02,
|
||||
copy_dirs = 0x04,
|
||||
|
||||
// operations will typically fail early if paths are empty or if they're not
|
||||
// inside a list of approved locations, like the prefix, %TEMP%, etc.
|
||||
//
|
||||
// this is to prevent mob from going on a deletion spree in case of bugs
|
||||
unsafe = 0x08
|
||||
};
|
||||
|
||||
MOB_ENUM_OPERATORS(flags);
|
||||
|
||||
|
||||
void touch(const context& cx, const fs::path& p);
|
||||
// creates the given file if it doesn't exist
|
||||
//
|
||||
void touch(const context& cx, const fs::path& p, flags f=noflags);
|
||||
|
||||
void create_directories(
|
||||
const context& cx, const fs::path& p, flags f=noflags);
|
||||
// creates all the directories in the given path
|
||||
//
|
||||
void create_directories(const context& cx, const fs::path& p, flags f=noflags);
|
||||
|
||||
void delete_directory(
|
||||
const context& cx, const fs::path& p, flags f=noflags);
|
||||
// deletes the given directory, recursive
|
||||
//
|
||||
// if deletion fails because of access denied, attemps to remove the readonly
|
||||
// flag on all files and tries again; this happens with some archives like 7z
|
||||
//
|
||||
void delete_directory(const context& cx, const fs::path& p, flags f=noflags);
|
||||
|
||||
void delete_file(
|
||||
const context& cx, const fs::path& p, flags f=noflags);
|
||||
// deletes the given file
|
||||
//
|
||||
void delete_file(const context& cx, const fs::path& p, flags f=noflags);
|
||||
|
||||
void delete_file_glob(
|
||||
const context& cx, const fs::path& glob, flags f=noflags);
|
||||
// deletes all files matching the glob in the glob's parent directory
|
||||
//
|
||||
void delete_file_glob(const context& cx, const fs::path& glob, flags f=noflags);
|
||||
|
||||
void remove_readonly(
|
||||
const context& cx, const fs::path& first);
|
||||
// removes the readonly flag for all files in `dir`, recursive
|
||||
//
|
||||
void remove_readonly(const context& cx, const fs::path& dir, flags f=noflags);
|
||||
|
||||
// renames `src` to `dest`, files or directories; fails if it already exists
|
||||
//
|
||||
void rename(
|
||||
const context& cx, const fs::path& src, const fs::path& dest);
|
||||
const context& cx, const fs::path& src, const fs::path& dest,
|
||||
flags f=noflags);
|
||||
|
||||
// moves a file or directory `src` into dir `dest_dir`, using the same name
|
||||
// (renames src to dest_dir/src.filename()); fails if it already exists
|
||||
//
|
||||
void move_to_directory(
|
||||
const context& cx, const fs::path& src, const fs::path& dest_dir);
|
||||
const context& cx, const fs::path& src, const fs::path& dest_dir,
|
||||
flags f=noflags);
|
||||
|
||||
// copies a single file `file` into `dest_dir`; if the file already exists, only
|
||||
// copies it if it's considered better (see comment on top); doesn't support
|
||||
// globs or directories
|
||||
//
|
||||
void copy_file_to_dir_if_better(
|
||||
const context& cx,
|
||||
const fs::path& file, const fs::path& dest_dir, flags f=noflags);
|
||||
|
||||
// same as copy_file_to_dir_if_better(), but the `dest_file` contains the
|
||||
// target filename instead of being constructed from dest_dir/src.filename()
|
||||
//
|
||||
void copy_file_to_file_if_better(
|
||||
const context& cx,
|
||||
const fs::path& src_file, const fs::path& dest_file, flags f=noflags);
|
||||
|
||||
// basically calls copy_file_to_dir_if_better() for every file matching the
|
||||
// glob; recursive
|
||||
//
|
||||
void copy_glob_to_dir_if_better(
|
||||
const context& cx,
|
||||
const fs::path& src_glob, const fs::path& dest_dir, flags f);
|
||||
|
||||
void swap_files(
|
||||
// renames `dest` to `src`, deleting `src` if it exists; if `backup` is given,
|
||||
// `src` is first renamed to it
|
||||
//
|
||||
// this attempts an atomic rename with ReplaceFile(), falls back to non-atomic
|
||||
// renames if it fails
|
||||
//
|
||||
void replace_file(
|
||||
const context& cx, const fs::path& src, const fs::path& dest,
|
||||
const fs::path& backup={}, flags f=noflags);
|
||||
|
||||
// reads the given file, converts it to utf8 from the given encoding, returns
|
||||
// the utf8 string; if `e` is `dont_know`, returns the bytes as-is
|
||||
//
|
||||
std::string read_text_file(
|
||||
const context& cx, encodings e, const fs::path& p, flags f=noflags);
|
||||
|
||||
// creates file `p`, writes the given utf8 string into it, converting the string
|
||||
// to the given encoding; if `e` is dont_know, the bytes are written as-is
|
||||
//
|
||||
void write_text_file(
|
||||
const context& cx, encodings e, const fs::path& p, std::string_view utf8,
|
||||
flags f=noflags);
|
||||
|
||||
// creates an archive `dest_file` and puts all the files matching `src_glob`
|
||||
// into it, ignoring any file in `ignore` by name
|
||||
//
|
||||
// uses tools::archiver
|
||||
//
|
||||
void archive_from_glob(
|
||||
const context& cx,
|
||||
const fs::path& src_glob, const fs::path& dest_file,
|
||||
const std::vector<std::string>& ignore);
|
||||
const std::vector<std::string>& ignore,
|
||||
flags f=noflags);
|
||||
|
||||
// creates an archive `dest_file` and puts all the files from `files` in it,
|
||||
// resolving relative paths against `files_root`
|
||||
//
|
||||
void archive_from_files(
|
||||
const context& cx,
|
||||
const std::vector<fs::path>& files, const fs::path& files_root,
|
||||
const fs::path& dest_file);
|
||||
const fs::path& dest_file,
|
||||
flags f=noflags);
|
||||
|
||||
} // namespace
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@ void sip::generate()
|
||||
{
|
||||
const std::string utf8 = op::read_text_file(cx(), encodings::utf8, src);
|
||||
op::write_text_file(cx(), encodings::acp, dest, utf8);
|
||||
op::swap_files(cx(), src, dest, backup);
|
||||
op::replace_file(cx(), src, dest, backup);
|
||||
}
|
||||
|
||||
run_tool(process_runner(process()
|
||||
|
||||
Reference in New Issue
Block a user