26namespace fs = std::filesystem;
51 , fs::path
const& path_file_dst
52 , fs::path
const& path_file_list
53 , uint64_t compression_level)
58 return_if(compression_level > 9, Error(
"E::Out-of-bounds compression level '{}'", compression_level));
60 logger(
"I::Gathering files to compress...");
61 std::ofstream file_list(path_file_list, std::ios::out | std::ios::trunc);
62 return_if(not file_list.is_open()
63 , Error(
"E::Could not open list of files '{}' to compress", path_file_list)
66 return_if(not fs::exists(path_dir_src), Error(
"E::Source directory '{}' does not exist", path_dir_src));
67 return_if(not fs::is_directory(path_dir_src), Error(
"E::Source '{}' is not a directory", path_dir_src));
69 for(
auto&& entry = fs::recursive_directory_iterator(path_dir_src)
70 ; entry != fs::recursive_directory_iterator()
74 fs::path path_entry = entry->path();
76 if(entry->is_regular_file() or entry->is_symlink())
79 << path_entry.lexically_relative(path_dir_src).string()
83 else if(entry->is_directory())
86 if(::access(path_entry.c_str(), R_OK | X_OK) != 0)
88 logger(
"I::Insufficient permissions to enter directory '{}'", path_entry);
89 entry.disable_recursion_pending();
93 if(fs::is_empty(path_entry))
96 << path_entry.lexically_relative(path_dir_src).string()
103 logger(
"I::Ignoring file '{}'", path_entry);
109 logger(
"I::Compression level: '{}'", compression_level);
110 logger(
"I::Compress filesystem to '{}'", path_file_dst);
113 .with_args(
"-i", path_dir_src,
"-o", path_file_dst)
114 .with_args(
"-l", compression_level)
115 .with_args(
"--input-list", path_file_list)
127[[nodiscard]]
inline Value<void> add(fs::path
const& path_file_binary, fs::path
const& path_file_layer)
130 std::ofstream file_binary(path_file_binary, std::ios::app | std::ios::binary);
131 return_if(not file_binary.is_open(), Error(
"E::Failed to open output file '{}'", path_file_binary));
132 std::ifstream file_layer(path_file_layer, std::ios::in | std::ios::binary);
133 return_if(not file_layer.is_open(), Error(
"E::Failed to open input file '{}'", path_file_layer));
135 uint64_t file_size = Try(fs::file_size(path_file_layer));
137 file_binary.write(
reinterpret_cast<char*
>(&file_size),
sizeof(file_size));
139 while( file_layer.read(buff,
sizeof(buff)) or file_layer.gcount() > 0 )
141 file_binary.write(buff, file_layer.gcount());
142 return_if(not file_binary, Error(
"E::Error writing data to file"));
144 logger(
"I::Included novel layer from file '{}'", path_file_layer);
157 if (not Try(fs::exists(path_dir_layers)) or not Try(fs::is_directory(path_dir_layers)))
159 return Error(
"E::Layers directory is missing or not a directory");
162 std::regex regex_layer(R
"(layer-[0-9]+\.layer)");
163 auto vec = Try(fs::directory_iterator(path_dir_layers)
164 | std::views::filter([](
auto&& e){
return e.is_regular_file(); })
165 | std::views::transform([](
auto&& e){
return e.path().filename().string(); })
166 | std::views::filter([&](
auto&& e){
return std::regex_search(e, regex_layer); })
167 | std::views::transform([](
auto&& e){
return std::stoi(e.substr(6, e.substr(6).find(
'.'))); })
168 | std::ranges::to<std::vector<int>>()
171 int next = (vec.empty())? 0 : *std::ranges::max_element(vec) + 1;
172 return_if(next > 999, Error(
"E::Maximum number of layers exceeded"));
192 fs::path
const& path_file_binary
193 , fs::path
const& path_dir_src
194 , fs::path
const& path_file_layer_tmp
195 , fs::path
const& path_file_list_tmp
196 , uint32_t layer_compression_level
198 , std::optional<fs::path>
const& path_dst = std::nullopt)
202 , path_file_layer_tmp
204 , layer_compression_level
210 case CommitMode::BINARY:
213 Pop(
add(path_file_binary, path_file_layer_tmp));
215 if(not Try(fs::remove(path_file_layer_tmp)))
217 logger(
"E::Could not erase layer file '{}'", path_file_layer_tmp.string());
219 logger(
"I::Filesystem appended to binary without errors");
222 case CommitMode::LAYER:
224 return_if(not path_dst.has_value(), Error(
"E::Layer mode requires a destination directory"));
225 return_if(not Try(fs::is_directory(path_dst.value())), Error(
"E::Destination should be a directory"));
228 fs::path layer_path = path_dst.value() / std::format(
"layer-{:03d}.layer", layer_num);
229 logger(
"I::Layer number: {}", layer_num);
230 logger(
"I::Layer path: {}", layer_path);
232 Try(fs::rename(path_file_layer_tmp, layer_path));
233 logger(
"I::Layer saved to '{}'", layer_path.string());
236 case CommitMode::FILE:
238 return_if(not path_dst.has_value(), Error(
"E::File mode requires a destination path"));
239 return_if(Try(fs::exists(path_dst.value())), Error(
"E::Destination file already exists"));
241 Try(fs::rename(path_file_layer_tmp, path_dst.value()));
242 logger(
"I::Layer saved to '{}'", path_dst.value().string());
247 std::ifstream file_list(path_file_list_tmp);
248 return_if(not file_list.is_open(), Error(
"E::Could not open file list for erasing files..."));
251 while(std::getline(file_list, line))
253 fs::path path_file_target = path_dir_src / line;
254 fs::path path_dir_parent = path_file_target.parent_path();
256 if(not Try(fs::remove(path_file_target)))
258 logger(
"E::Could not remove file {}", path_file_target.string());
261 if(Try(fs::is_empty(path_dir_parent)) and not Try(fs::remove(path_dir_parent)))
263 logger(
"E::Could not remove directory {}", path_dir_parent.string());
276 for(uint64_t index = 0;
auto const& layer : layers.
get_layers())
278 std::cout << std::format(
"{}:{}:{}:{}\n", index, layer.offset, layer.size, layer.path.string());
Manages external DwarFS layer files and directories for the filesystem controller.
std::vector< Layer > const & get_layers() const
Retrieves the collected layer file paths with offsets.
Enhanced error handling framework built on std::expected.
Layer management for DwarFS filesystems.
A library for manipulating environment variables.
#define logger(fmt,...)
Compile-time log level dispatch macro with automatic location capture.
Value< fs::path > search_path(std::string const &query)
Search the directories in the PATH variable for the given input file name.
Filesystem layer management command implementation.
CommitMode
Commit changes into a novel layer (binary/layer/file modes)
Value< void > add(fs::path const &path_file_binary, fs::path const &path_file_layer)
Includes a filesystem in the target FlatImage.
Value< uint64_t > find_next_layer_number(fs::path const &path_dir_layers)
Finds the next available layer number in the layers directory.
Value< void > create(fs::path const &path_dir_src, fs::path const &path_file_dst, fs::path const &path_file_list, uint64_t compression_level)
Creates a layer (filesystem) from a source directory.
void list(ns_filesystems::ns_layers::Layers const &layers)
Lists all layers in the format index:offset:size:path.
Enhanced expected type with integrated logging capabilities.
A library to spawn sub-processes in linux.