moved unsafe flag check to check()
This commit is contained in:
isanae
2020-12-03 17:44:52 -05:00
parent b9d4c9e4ab
commit dbbee9a1d9
3 changed files with 141 additions and 58 deletions
+53 -41
View File
@@ -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
View File
@@ -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
View File
@@ -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()