mirror of
https://github.com/mgree/ffs.git
synced 2024-09-11 19:17:40 +03:00
Minor tweaks (#71)
* satisfy clippy, cleanup format strings and formatting * build on macos-latest * update workflow versions
This commit is contained in:
parent
56ba6890ba
commit
16396b8a28
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- macos-11
|
- macos-latest
|
||||||
- ubuntu-latest
|
- ubuntu-latest
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@ -30,7 +30,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build ffs/pack/unpack and run unit tests
|
- name: Build ffs/pack/unpack and run unit tests
|
||||||
run: |
|
run: |
|
||||||
@ -46,7 +46,7 @@ jobs:
|
|||||||
run: PATH="$(pwd)/target/release:$PATH" ./run_tests.sh unpack
|
run: PATH="$(pwd)/target/release:$PATH" ./run_tests.sh unpack
|
||||||
|
|
||||||
- name: Upload macOS release build
|
- name: Upload macOS release build
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
if: contains(matrix.os, 'macos')
|
if: contains(matrix.os, 'macos')
|
||||||
with:
|
with:
|
||||||
name: ffs.macos
|
name: ffs.macos
|
||||||
@ -56,7 +56,7 @@ jobs:
|
|||||||
target/release/unpack
|
target/release/unpack
|
||||||
|
|
||||||
- name: Upload Linux release build
|
- name: Upload Linux release build
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
if: contains(matrix.os, 'ubuntu')
|
if: contains(matrix.os, 'ubuntu')
|
||||||
with:
|
with:
|
||||||
name: ffs.linux
|
name: ffs.linux
|
||||||
@ -80,10 +80,10 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Download binaries
|
- name: Download binaries
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4
|
||||||
|
|
||||||
- name: Install R
|
- name: Install R
|
||||||
uses: r-lib/actions/setup-r@v2
|
uses: r-lib/actions/setup-r@v2
|
||||||
@ -103,7 +103,7 @@ jobs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
- name: Upload Linux benchmark data
|
- name: Upload Linux benchmark data
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
if: contains(matrix.os, 'ubuntu')
|
if: contains(matrix.os, 'ubuntu')
|
||||||
with:
|
with:
|
||||||
name: benchmarks.linux
|
name: benchmarks.linux
|
||||||
@ -116,7 +116,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download binaries
|
- name: Download binaries
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4
|
||||||
|
|
||||||
- name: Rename binaries
|
- name: Rename binaries
|
||||||
run: |
|
run: |
|
||||||
|
@ -34,14 +34,14 @@ fn main() {
|
|||||||
Format::Json => {
|
Format::Json => {
|
||||||
let fs: FS<format::json::Value> = FS::new(config);
|
let fs: FS<format::json::Value> = FS::new(config);
|
||||||
|
|
||||||
info!("mounting on {:?} with options {:?}", mount, options);
|
info!("mounting on {} with options {options:?}", mount.display());
|
||||||
match fuser::mount2(fs, &mount, &options) {
|
match fuser::mount2(fs, &mount, &options) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
info!("unmounted");
|
info!("unmounted");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("I/O error: {}", e);
|
error!("I/O error: {e}");
|
||||||
ERROR_STATUS_FUSE
|
ERROR_STATUS_FUSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,14 +49,14 @@ fn main() {
|
|||||||
Format::Toml => {
|
Format::Toml => {
|
||||||
let fs: FS<format::toml::Value> = FS::new(config);
|
let fs: FS<format::toml::Value> = FS::new(config);
|
||||||
|
|
||||||
info!("mounting on {:?} with options {:?}", mount, options);
|
info!("mounting on {} with options {options:?}", mount.display());
|
||||||
match fuser::mount2(fs, &mount, &options) {
|
match fuser::mount2(fs, &mount, &options) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
info!("unmounted");
|
info!("unmounted");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("I/O error: {}", e);
|
error!("I/O error: {e}");
|
||||||
ERROR_STATUS_FUSE
|
ERROR_STATUS_FUSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,14 +64,14 @@ fn main() {
|
|||||||
Format::Yaml => {
|
Format::Yaml => {
|
||||||
let fs: FS<format::yaml::Value> = FS::new(config);
|
let fs: FS<format::yaml::Value> = FS::new(config);
|
||||||
|
|
||||||
info!("mounting on {:?} with options {:?}", mount, options);
|
info!("mounting on {} with options {options:?}", mount.display());
|
||||||
match fuser::mount2(fs, &mount, &options) {
|
match fuser::mount2(fs, &mount, &options) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
info!("unmounted");
|
info!("unmounted");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("I/O error: {}", e);
|
error!("I/O error: {e}");
|
||||||
ERROR_STATUS_FUSE
|
ERROR_STATUS_FUSE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ fn main() {
|
|||||||
if cleanup_mount {
|
if cleanup_mount {
|
||||||
if mount.exists() {
|
if mount.exists() {
|
||||||
if let Err(e) = std::fs::remove_dir(&mount) {
|
if let Err(e) = std::fs::remove_dir(&mount) {
|
||||||
warn!("Unable to clean up mountpoint '{}': {}", mount.display(), e);
|
warn!("Unable to clean up mountpoint '{}': {e}", mount.display());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
|
@ -9,7 +9,7 @@ use std::path::PathBuf;
|
|||||||
use std::str;
|
use std::str;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
use ffs::config::Config;
|
use ffs::config::Config;
|
||||||
use ffs::config::Symlink;
|
use ffs::config::Symlink;
|
||||||
@ -40,6 +40,12 @@ pub struct Pack {
|
|||||||
regex: Regex,
|
regex: Regex,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Pack {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Pack {
|
impl Pack {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -75,7 +81,7 @@ impl Pack {
|
|||||||
let mut link_follower = path.clone();
|
let mut link_follower = path.clone();
|
||||||
while link_follower.is_symlink() {
|
while link_follower.is_symlink() {
|
||||||
if link_trail.contains(&link_follower) {
|
if link_trail.contains(&link_follower) {
|
||||||
error!("Symlink loop detected at {:?}.", link_follower);
|
error!("Symlink loop detected at {}.", link_follower.display());
|
||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
}
|
}
|
||||||
link_trail.push(link_follower.clone());
|
link_trail.push(link_follower.clone());
|
||||||
@ -92,8 +98,8 @@ impl Pack {
|
|||||||
// Err(_) => {
|
// Err(_) => {
|
||||||
// // Cannot call xattr::get on ._ file
|
// // Cannot call xattr::get on ._ file
|
||||||
// warn!(
|
// warn!(
|
||||||
// "._ files, like {:?}, prevent xattr calls. It will be encoded in base64.",
|
// "._ files, like {}, prevent xattr calls. It will be encoded in base64.",
|
||||||
// link_follower
|
// link_follower.display()
|
||||||
// );
|
// );
|
||||||
// path_type = b"bytes".to_vec()
|
// path_type = b"bytes".to_vec()
|
||||||
// }
|
// }
|
||||||
@ -130,8 +136,8 @@ impl Pack {
|
|||||||
{
|
{
|
||||||
// the symlink is broken, so don't pack this file.
|
// the symlink is broken, so don't pack this file.
|
||||||
warn!(
|
warn!(
|
||||||
"The symlink at the end of the chain starting from '{:?}' is broken.",
|
"The symlink at the end of the chain starting from '{}' is broken.",
|
||||||
path
|
path.display()
|
||||||
);
|
);
|
||||||
for link in link_trail {
|
for link in link_trail {
|
||||||
let symlink_map_data = &self.symlinks[&link];
|
let symlink_map_data = &self.symlinks[&link];
|
||||||
@ -150,16 +156,16 @@ impl Pack {
|
|||||||
let canonicalized = link_follower.canonicalize()?;
|
let canonicalized = link_follower.canonicalize()?;
|
||||||
if path.starts_with(&canonicalized) {
|
if path.starts_with(&canonicalized) {
|
||||||
error!(
|
error!(
|
||||||
"The symlink {:?} points to some ancestor directory: {:?}, causing an infinite loop.",
|
"The symlink {} points to some ancestor directory: {}, causing an infinite loop.",
|
||||||
path, canonicalized
|
path.display(), canonicalized.display(),
|
||||||
);
|
);
|
||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
}
|
}
|
||||||
if !config.allow_symlink_escape
|
if !config.allow_symlink_escape
|
||||||
&& !canonicalized.starts_with(config.mount.as_ref().unwrap())
|
&& !canonicalized.starts_with(config.mount.as_ref().unwrap())
|
||||||
{
|
{
|
||||||
warn!("The symlink {:?} points to some file outside of the directory being packed. \
|
warn!("The symlink {} points to some file outside of the directory being packed. \
|
||||||
Specify --allow-symlink-escape to allow pack to follow this symlink.", path);
|
Specify --allow-symlink-escape to allow pack to follow this symlink.", path.display());
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,14 +176,14 @@ impl Pack {
|
|||||||
// none of the symlinks on the chain have an xattr. Use the actual file's xattr
|
// none of the symlinks on the chain have an xattr. Use the actual file's xattr
|
||||||
if path_type.is_empty() {
|
if path_type.is_empty() {
|
||||||
let canonicalized = path.canonicalize()?;
|
let canonicalized = path.canonicalize()?;
|
||||||
path_type = match xattr::get(&canonicalized, "user.type") {
|
path_type = match xattr::get(canonicalized, "user.type") {
|
||||||
Ok(Some(xattr_type)) if config.allow_xattr => xattr_type,
|
Ok(Some(xattr_type)) if config.allow_xattr => xattr_type,
|
||||||
Ok(_) => b"auto".to_vec(),
|
Ok(_) => b"auto".to_vec(),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// Cannot call xattr::get on ._ file
|
// Cannot call xattr::get on ._ file
|
||||||
warn!(
|
warn!(
|
||||||
"._ files, like {:?}, prevent xattr calls. It will be encoded in base64.",
|
"._ files, like {}, prevent xattr calls. It will be encoded in base64.",
|
||||||
path
|
path.display(),
|
||||||
);
|
);
|
||||||
b"bytes".to_vec()
|
b"bytes".to_vec()
|
||||||
}
|
}
|
||||||
@ -191,19 +197,18 @@ impl Pack {
|
|||||||
if path.is_dir() && (path_type == "auto" || path_type != "named" && path_type != "list") {
|
if path.is_dir() && (path_type == "auto" || path_type != "named" && path_type != "list") {
|
||||||
if path_type != "auto" {
|
if path_type != "auto" {
|
||||||
warn!(
|
warn!(
|
||||||
"Unknown directory type '{}'. Possible types are 'named' or 'list'. \
|
"Unknown directory type '{path_type}'. Possible types are 'named' or 'list'. \
|
||||||
Resolving type automatically.",
|
Resolving type automatically."
|
||||||
path_type
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let all_files_begin_with_num = fs::read_dir(path.clone())?
|
let all_files_begin_with_num = fs::read_dir(path.clone())?
|
||||||
.map(|res| res.map(|e| e.path()))
|
.map(|res| res.map(|e| e.path()))
|
||||||
.map(|e| e.unwrap().file_name().unwrap().to_str().unwrap().to_owned())
|
.map(|e| e.unwrap().file_name().unwrap().to_str().unwrap().to_owned())
|
||||||
.all(|filename| {
|
.all(|filename| {
|
||||||
filename.chars().nth(0).unwrap().is_digit(10)
|
filename.chars().nth(0).unwrap().is_ascii_digit()
|
||||||
|| filename.len() > 1
|
|| filename.len() > 1
|
||||||
&& filename.chars().nth(0).unwrap() == '-'
|
&& filename.chars().nth(0).unwrap() == '-'
|
||||||
&& filename.chars().nth(1).unwrap().is_digit(10)
|
&& filename.chars().nth(1).unwrap().is_ascii_digit()
|
||||||
});
|
});
|
||||||
if all_files_begin_with_num {
|
if all_files_begin_with_num {
|
||||||
path_type = "list"
|
path_type = "list"
|
||||||
@ -212,8 +217,6 @@ impl Pack {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("type of {:?} is {}", path, path_type);
|
|
||||||
|
|
||||||
// return the value based on determined type
|
// return the value based on determined type
|
||||||
match path_type {
|
match path_type {
|
||||||
"named" => {
|
"named" => {
|
||||||
@ -227,11 +230,11 @@ impl Pack {
|
|||||||
for child in &children {
|
for child in &children {
|
||||||
let child_name = child.file_name().unwrap().to_str().unwrap();
|
let child_name = child.file_name().unwrap().to_str().unwrap();
|
||||||
if config.ignored_file(child_name) {
|
if config.ignored_file(child_name) {
|
||||||
warn!("skipping ignored file {:?}", child_name);
|
warn!("skipping ignored file {}", child.display());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let name: String;
|
let name: String;
|
||||||
match xattr::get(&child, "user.original_name") {
|
match xattr::get(child, "user.original_name") {
|
||||||
Ok(Some(original_name)) if config.allow_xattr => {
|
Ok(Some(original_name)) if config.allow_xattr => {
|
||||||
let old_name = str::from_utf8(&original_name).unwrap();
|
let old_name = str::from_utf8(&original_name).unwrap();
|
||||||
if !config.valid_name(old_name) {
|
if !config.valid_name(old_name) {
|
||||||
@ -250,14 +253,14 @@ impl Pack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
let value = self.pack(child.clone(), &config)?;
|
let value = self.pack(child.clone(), config)?;
|
||||||
self.depth -= 1;
|
self.depth -= 1;
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
entries.insert(name, value);
|
entries.insert(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(V::from_named_dir(entries, &config)))
|
Ok(Some(V::from_named_dir(entries, config)))
|
||||||
}
|
}
|
||||||
"list" => {
|
"list" => {
|
||||||
let mut numbers_filenames_paths = fs::read_dir(path.clone())?
|
let mut numbers_filenames_paths = fs::read_dir(path.clone())?
|
||||||
@ -296,23 +299,21 @@ impl Pack {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
numbers_filenames_paths.sort();
|
numbers_filenames_paths.sort();
|
||||||
|
|
||||||
info!("parsed numbers and filenames {:?}", numbers_filenames_paths);
|
|
||||||
|
|
||||||
let mut entries = Vec::with_capacity(numbers_filenames_paths.len());
|
let mut entries = Vec::with_capacity(numbers_filenames_paths.len());
|
||||||
for (_, filename, child) in numbers_filenames_paths {
|
for (_, filename, child) in numbers_filenames_paths {
|
||||||
if config.ignored_file(&filename) {
|
if config.ignored_file(&filename) {
|
||||||
warn!("skipping ignored file {:?}", child);
|
warn!("skipping ignored file {}", child.display());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
let value = self.pack(child, &config)?;
|
let value = self.pack(child, config)?;
|
||||||
self.depth -= 1;
|
self.depth -= 1;
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
entries.push(value);
|
entries.push(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(V::from_list_dir(entries, &config)))
|
Ok(Some(V::from_list_dir(entries, config)))
|
||||||
}
|
}
|
||||||
typ => {
|
typ => {
|
||||||
if let Ok(t) = Typ::from_str(typ) {
|
if let Ok(t) = Typ::from_str(typ) {
|
||||||
@ -325,14 +326,13 @@ impl Pack {
|
|||||||
if config.add_newlines && contents.ends_with('\n') {
|
if config.add_newlines && contents.ends_with('\n') {
|
||||||
contents.truncate(contents.len() - 1);
|
contents.truncate(contents.len() - 1);
|
||||||
}
|
}
|
||||||
Ok(Some(V::from_string(t, contents, &config)))
|
Ok(Some(V::from_string(t, contents, config)))
|
||||||
}
|
}
|
||||||
Ok(_) | Err(_) => Ok(Some(V::from_bytes(contents, &config))),
|
Ok(_) | Err(_) => Ok(Some(V::from_bytes(contents, config))),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!(
|
error!(
|
||||||
"This error should never be called. Received undetected and unknown type '{}' for file '{}'",
|
"Received undetected and unknown type '{typ}' for file '{}'",
|
||||||
typ,
|
|
||||||
path.display()
|
path.display()
|
||||||
);
|
);
|
||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
@ -344,12 +344,11 @@ impl Pack {
|
|||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let config = Config::from_pack_args();
|
let config = Config::from_pack_args();
|
||||||
debug!("received config: {:?}", config);
|
|
||||||
|
|
||||||
let mount = match &config.mount {
|
let mount = match &config.mount {
|
||||||
Some(mount) => mount,
|
Some(mount) => mount,
|
||||||
None => {
|
None => {
|
||||||
error!("Cannot pack unspecified directory.");
|
error!("You must specify a directory to pack.");
|
||||||
std::process::exit(ERROR_STATUS_CLI);
|
std::process::exit(ERROR_STATUS_CLI);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use fuser::FileType;
|
use fuser::FileType;
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@ -33,11 +33,11 @@ where
|
|||||||
.open(&path)?;
|
.open(&path)?;
|
||||||
|
|
||||||
// write `s` into that file
|
// write `s` into that file
|
||||||
f.write(s.as_bytes())?;
|
f.write_all(s.as_bytes())?;
|
||||||
|
|
||||||
// set metadata according to `t`
|
// set metadata according to `t`
|
||||||
if config.allow_xattr {
|
if config.allow_xattr {
|
||||||
xattr::set(&path, "user.type", format!("{}", t).as_bytes())?;
|
xattr::set(&path, "user.type", t.to_string().as_bytes())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
format::Node::Bytes(b) => {
|
format::Node::Bytes(b) => {
|
||||||
@ -52,7 +52,7 @@ where
|
|||||||
|
|
||||||
// set metadata to bytes
|
// set metadata to bytes
|
||||||
if config.allow_xattr {
|
if config.allow_xattr {
|
||||||
xattr::set(&path, "user.type", format!("{}", Typ::Bytes).as_bytes())?;
|
xattr::set(&path, "user.type", Typ::Bytes.to_string().as_bytes())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
format::Node::List(vs) => {
|
format::Node::List(vs) => {
|
||||||
@ -71,9 +71,9 @@ where
|
|||||||
for (i, child) in vs.into_iter().enumerate() {
|
for (i, child) in vs.into_iter().enumerate() {
|
||||||
// TODO(mmg) 2021-06-08 ability to add prefixes
|
// TODO(mmg) 2021-06-08 ability to add prefixes
|
||||||
let name = if config.pad_element_names {
|
let name = if config.pad_element_names {
|
||||||
format!("{:0width$}", i, width = width)
|
format!("{i:0width$}")
|
||||||
} else {
|
} else {
|
||||||
format!("{}", i)
|
format!("{i}")
|
||||||
};
|
};
|
||||||
let child_path = path.join(name);
|
let child_path = path.join(name);
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ where
|
|||||||
}
|
}
|
||||||
ffs::config::Munge::Filter => {
|
ffs::config::Munge::Filter => {
|
||||||
// TODO(mmg) 2023-03-06 support logging
|
// TODO(mmg) 2023-03-06 support logging
|
||||||
warn!("skipping '{}'", field);
|
warn!("skipping '{field}'");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,12 +135,11 @@ where
|
|||||||
|
|
||||||
fn main() -> std::io::Result<()> {
|
fn main() -> std::io::Result<()> {
|
||||||
let config = Config::from_unpack_args();
|
let config = Config::from_unpack_args();
|
||||||
debug!("received config: {:?}", config);
|
|
||||||
|
|
||||||
let mount = match &config.mount {
|
let mount = match &config.mount {
|
||||||
Some(mount) => mount.clone(),
|
Some(mount) => mount.clone(),
|
||||||
None => {
|
None => {
|
||||||
error!("Directory not specified");
|
error!("You must specify a directory to unpack.");
|
||||||
std::process::exit(ERROR_STATUS_CLI);
|
std::process::exit(ERROR_STATUS_CLI);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -154,7 +153,7 @@ fn main() -> std::io::Result<()> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = match &config.input_format {
|
match &config.input_format {
|
||||||
Format::Json => {
|
Format::Json => {
|
||||||
let value = JsonValue::from_reader(reader);
|
let value = JsonValue::from_reader(reader);
|
||||||
if value.kind() == FileType::Directory {
|
if value.kind() == FileType::Directory {
|
||||||
@ -182,7 +181,5 @@ fn main() -> std::io::Result<()> {
|
|||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
100
src/config.rs
100
src/config.rs
@ -133,7 +133,7 @@ impl Config {
|
|||||||
} else if shell == "zsh" {
|
} else if shell == "zsh" {
|
||||||
clap::Shell::Zsh
|
clap::Shell::Zsh
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Can't generate completions for '{}'.", shell);
|
eprintln!("Can't generate completions for '{shell}'.");
|
||||||
std::process::exit(ERROR_STATUS_CLI);
|
std::process::exit(ERROR_STATUS_CLI);
|
||||||
};
|
};
|
||||||
cli::ffs().gen_completions_to("ffs", shell, &mut std::io::stdout());
|
cli::ffs().gen_completions_to("ffs", shell, &mut std::io::stdout());
|
||||||
@ -172,7 +172,7 @@ impl Config {
|
|||||||
Some(s) => match str::parse(s) {
|
Some(s) => match str::parse(s) {
|
||||||
Ok(munge) => munge,
|
Ok(munge) => munge,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!("Invalid `--munge` mode '{}', using 'rename'.", s);
|
warn!("Invalid `--munge` mode '{s}', using 'rename'.");
|
||||||
Munge::Rename
|
Munge::Rename
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -183,9 +183,8 @@ impl Config {
|
|||||||
Ok(filemode) => filemode,
|
Ok(filemode) => filemode,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!(
|
error!(
|
||||||
"Couldn't parse `--mode {}`: {}.",
|
"Couldn't parse `--mode {}`: {e}.",
|
||||||
args.value_of("FILEMODE").unwrap(),
|
args.value_of("FILEMODE").unwrap()
|
||||||
e
|
|
||||||
);
|
);
|
||||||
std::process::exit(ERROR_STATUS_CLI)
|
std::process::exit(ERROR_STATUS_CLI)
|
||||||
}
|
}
|
||||||
@ -207,9 +206,8 @@ impl Config {
|
|||||||
Ok(filemode) => filemode,
|
Ok(filemode) => filemode,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!(
|
error!(
|
||||||
"Couldn't parse `--dirmode {}`: {}.",
|
"Couldn't parse `--dirmode {}`: {e}.",
|
||||||
args.value_of("DIRMODE").unwrap(),
|
args.value_of("DIRMODE").unwrap()
|
||||||
e
|
|
||||||
);
|
);
|
||||||
std::process::exit(ERROR_STATUS_CLI)
|
std::process::exit(ERROR_STATUS_CLI)
|
||||||
}
|
}
|
||||||
@ -223,8 +221,7 @@ impl Config {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
let euid = unsafe { libc::geteuid() };
|
let euid = unsafe { libc::geteuid() };
|
||||||
warn!(
|
warn!(
|
||||||
"Couldn't parse '{}' as a uid ({}), defaulting to effective uid ({})",
|
"Couldn't parse '{uid_string}' as a uid ({e}), defaulting to effective uid ({euid})"
|
||||||
uid_string, e, euid
|
|
||||||
);
|
);
|
||||||
config.uid = euid;
|
config.uid = euid;
|
||||||
}
|
}
|
||||||
@ -237,8 +234,7 @@ impl Config {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
let egid = unsafe { libc::getegid() };
|
let egid = unsafe { libc::getegid() };
|
||||||
warn!(
|
warn!(
|
||||||
"Couldn't parse '{}' as a gid ({}), defaulting to effective gid ({})",
|
"Couldn't parse '{gid_string}' as a gid ({e}), defaulting to effective gid ({egid})"
|
||||||
gid_string, e, egid
|
|
||||||
);
|
);
|
||||||
config.gid = egid;
|
config.gid = egid;
|
||||||
}
|
}
|
||||||
@ -272,8 +268,7 @@ impl Config {
|
|||||||
match e {
|
match e {
|
||||||
format::ParseFormatError::NoSuchFormat(s) => {
|
format::ParseFormatError::NoSuchFormat(s) => {
|
||||||
warn!(
|
warn!(
|
||||||
"Unrecognized format '{}', inferring from {}.",
|
"Unrecognized format '{s}', inferring from {}.",
|
||||||
s,
|
|
||||||
output.display(),
|
output.display(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -323,10 +318,9 @@ impl Config {
|
|||||||
}
|
}
|
||||||
// If the mountpoint can't be created, give up and tell the user about --mount.
|
// If the mountpoint can't be created, give up and tell the user about --mount.
|
||||||
if let Err(e) = std::fs::create_dir(&mount_dir) {
|
if let Err(e) = std::fs::create_dir(&mount_dir) {
|
||||||
error!("Couldn't create mountpoint '{}': {}. Use `--mount MOUNT` to specify a mountpoint.",
|
error!("Couldn't create mountpoint '{}': {e}. Use `--mount MOUNT` to specify a mountpoint.",
|
||||||
mount_dir.display(),
|
mount_dir.display(),
|
||||||
e
|
);
|
||||||
);
|
|
||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
}
|
}
|
||||||
// We did it!
|
// We did it!
|
||||||
@ -426,9 +420,8 @@ impl Config {
|
|||||||
// If the mountpoint can't be created, give up and tell the user about --mount.
|
// If the mountpoint can't be created, give up and tell the user about --mount.
|
||||||
if let Err(e) = std::fs::create_dir(&mount_dir) {
|
if let Err(e) = std::fs::create_dir(&mount_dir) {
|
||||||
error!(
|
error!(
|
||||||
"Couldn't create mountpoint '{}': {}. Use `--mount MOUNT` to specify a mountpoint.",
|
"Couldn't create mountpoint '{}': {e}. Use `--mount MOUNT` to specify a mountpoint.",
|
||||||
mount_dir.display(),
|
mount_dir.display()
|
||||||
e
|
|
||||||
);
|
);
|
||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
}
|
}
|
||||||
@ -473,11 +466,15 @@ impl Config {
|
|||||||
.and_then(|s| s.parse::<Format>())
|
.and_then(|s| s.parse::<Format>())
|
||||||
{
|
{
|
||||||
Ok(format) => format,
|
Ok(format) => format,
|
||||||
Err(_) => {
|
Err(e) => {
|
||||||
warn!(
|
match e {
|
||||||
"Unrecognized format {}, defaulting to JSON.",
|
format::ParseFormatError::NoFormatProvided => {
|
||||||
input_source.display()
|
warn!("No extension detected, defaulting to JSON.")
|
||||||
);
|
}
|
||||||
|
format::ParseFormatError::NoSuchFormat(s) => {
|
||||||
|
warn!("Unrecognized extension {s}, defaulting to JSON.")
|
||||||
|
}
|
||||||
|
};
|
||||||
Format::Json
|
Format::Json
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -501,10 +498,7 @@ impl Config {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
match e {
|
match e {
|
||||||
format::ParseFormatError::NoSuchFormat(s) => {
|
format::ParseFormatError::NoSuchFormat(s) => {
|
||||||
warn!(
|
warn!("Unrecognized format '{s}', inferring from input and output.")
|
||||||
"Unrecognized format '{}', inferring from input and output.",
|
|
||||||
s
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
format::ParseFormatError::NoFormatProvided => {
|
format::ParseFormatError::NoFormatProvided => {
|
||||||
debug!("Inferring output format from input.")
|
debug!("Inferring output format from input.")
|
||||||
@ -519,8 +513,8 @@ impl Config {
|
|||||||
Ok(format) => format,
|
Ok(format) => format,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!(
|
warn!(
|
||||||
"Unrecognized format {}, defaulting to input format '{}'.",
|
"Unrecognized format {s}, defaulting to input format '{}'.",
|
||||||
s, config.input_format
|
config.input_format
|
||||||
);
|
);
|
||||||
config.input_format
|
config.input_format
|
||||||
}
|
}
|
||||||
@ -560,7 +554,7 @@ impl Config {
|
|||||||
} else if shell == "zsh" {
|
} else if shell == "zsh" {
|
||||||
clap::Shell::Zsh
|
clap::Shell::Zsh
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Can't generate completions for '{}'.", shell);
|
eprintln!("Can't generate completions for '{shell}'.");
|
||||||
std::process::exit(ERROR_STATUS_CLI);
|
std::process::exit(ERROR_STATUS_CLI);
|
||||||
};
|
};
|
||||||
cli::unpack().gen_completions_to("unpack", shell, &mut std::io::stdout());
|
cli::unpack().gen_completions_to("unpack", shell, &mut std::io::stdout());
|
||||||
@ -597,7 +591,7 @@ impl Config {
|
|||||||
Some(s) => match str::parse(s) {
|
Some(s) => match str::parse(s) {
|
||||||
Ok(munge) => munge,
|
Ok(munge) => munge,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!("Invalid `--munge` mode '{}', using 'rename'.", s);
|
warn!("Invalid `--munge` mode '{s}', using 'rename'.");
|
||||||
Munge::Rename
|
Munge::Rename
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -623,7 +617,7 @@ impl Config {
|
|||||||
// infer and create mountpoint from filename as possible
|
// infer and create mountpoint from filename as possible
|
||||||
config.mount = match args.value_of("INTO") {
|
config.mount = match args.value_of("INTO") {
|
||||||
Some(mount_point) => {
|
Some(mount_point) => {
|
||||||
match std::fs::create_dir(&mount_point) {
|
match std::fs::create_dir(mount_point) {
|
||||||
Ok(_) => Some(PathBuf::from(mount_point)),
|
Ok(_) => Some(PathBuf::from(mount_point)),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// if dir is empty then we can use it
|
// if dir is empty then we can use it
|
||||||
@ -633,10 +627,7 @@ impl Config {
|
|||||||
Some(PathBuf::from(mount_point))
|
Some(PathBuf::from(mount_point))
|
||||||
} else {
|
} else {
|
||||||
// dir exists but is not empty
|
// dir exists but is not empty
|
||||||
error!(
|
error!("Directory `{mount_point}` already exists and is not empty.");
|
||||||
"Directory `{}` already exists and is not empty.",
|
|
||||||
mount_point
|
|
||||||
);
|
|
||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -670,9 +661,8 @@ impl Config {
|
|||||||
// If the mountpoint can't be created, give up and tell the user about --mount.
|
// If the mountpoint can't be created, give up and tell the user about --mount.
|
||||||
if let Err(e) = std::fs::create_dir(&mount_dir) {
|
if let Err(e) = std::fs::create_dir(&mount_dir) {
|
||||||
error!(
|
error!(
|
||||||
"Couldn't create directory '{}': {}. Use `--into DIRECTORY` to specify a directory.",
|
"Couldn't create directory '{}': {e}. Use `--into DIRECTORY` to specify a directory.",
|
||||||
mount_dir.display(),
|
mount_dir.display()
|
||||||
e
|
|
||||||
);
|
);
|
||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
}
|
}
|
||||||
@ -701,7 +691,7 @@ impl Config {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
match e {
|
match e {
|
||||||
format::ParseFormatError::NoSuchFormat(s) => {
|
format::ParseFormatError::NoSuchFormat(s) => {
|
||||||
warn!("Unrecognized format '{}', inferring from input.", s)
|
warn!("Unrecognized format '{s}', inferring from input.")
|
||||||
}
|
}
|
||||||
format::ParseFormatError::NoFormatProvided => {
|
format::ParseFormatError::NoFormatProvided => {
|
||||||
debug!("Inferring format from input.")
|
debug!("Inferring format from input.")
|
||||||
@ -750,7 +740,7 @@ impl Config {
|
|||||||
} else if shell == "zsh" {
|
} else if shell == "zsh" {
|
||||||
clap::Shell::Zsh
|
clap::Shell::Zsh
|
||||||
} else {
|
} else {
|
||||||
eprintln!("Can't generate completions for '{}'.", shell);
|
eprintln!("Can't generate completions for '{shell}'.");
|
||||||
std::process::exit(ERROR_STATUS_CLI);
|
std::process::exit(ERROR_STATUS_CLI);
|
||||||
};
|
};
|
||||||
cli::pack().gen_completions_to("pack", shell, &mut std::io::stdout());
|
cli::pack().gen_completions_to("pack", shell, &mut std::io::stdout());
|
||||||
@ -794,10 +784,7 @@ impl Config {
|
|||||||
Some(s) => match str::parse(s) {
|
Some(s) => match str::parse(s) {
|
||||||
Ok(depth) => Some(depth),
|
Ok(depth) => Some(depth),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
error!(
|
error!("Invalid `--max-depth` '{s}', must be a non-negative integer.");
|
||||||
"Invalid `--max-depth` '{}', must be a non-negative integer.",
|
|
||||||
s
|
|
||||||
);
|
|
||||||
std::process::exit(ERROR_STATUS_CLI);
|
std::process::exit(ERROR_STATUS_CLI);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -810,7 +797,7 @@ impl Config {
|
|||||||
Some(s) => match str::parse(s) {
|
Some(s) => match str::parse(s) {
|
||||||
Ok(munge) => munge,
|
Ok(munge) => munge,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!("Invalid `--munge` mode '{}', using 'rename'.", s);
|
warn!("Invalid `--munge` mode '{s}', using 'rename'.");
|
||||||
Munge::Rename
|
Munge::Rename
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -866,10 +853,7 @@ impl Config {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
match e {
|
match e {
|
||||||
format::ParseFormatError::NoSuchFormat(s) => {
|
format::ParseFormatError::NoSuchFormat(s) => {
|
||||||
warn!(
|
warn!("Unrecognized format '{s}', inferring from input and output.")
|
||||||
"Unrecognized format '{}', inferring from input and output.",
|
|
||||||
s
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
format::ParseFormatError::NoFormatProvided => {
|
format::ParseFormatError::NoFormatProvided => {
|
||||||
debug!("Inferring output format from input.")
|
debug!("Inferring output format from input.")
|
||||||
@ -884,8 +868,8 @@ impl Config {
|
|||||||
Ok(format) => format,
|
Ok(format) => format,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!(
|
warn!(
|
||||||
"Unrecognized format {}, defaulting to input format '{}'.",
|
"Unrecognized format {s}, defaulting to input format '{}'.",
|
||||||
s, config.input_format
|
config.input_format
|
||||||
);
|
);
|
||||||
config.input_format
|
config.input_format
|
||||||
}
|
}
|
||||||
@ -915,7 +899,7 @@ impl Config {
|
|||||||
} else if s == ".." {
|
} else if s == ".." {
|
||||||
"_..".into()
|
"_..".into()
|
||||||
} else {
|
} else {
|
||||||
s.replace("\0", "_NUL_").replace("/", "_SLASH_")
|
s.replace('\0', "_NUL_").replace('/', "_SLASH_")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,8 +940,8 @@ impl Config {
|
|||||||
Input::Stdin => Some(Box::new(std::io::stdin())),
|
Input::Stdin => Some(Box::new(std::io::stdin())),
|
||||||
Input::File(file) => {
|
Input::File(file) => {
|
||||||
let fmt = self.input_format;
|
let fmt = self.input_format;
|
||||||
let file = std::fs::File::open(&file).unwrap_or_else(|e| {
|
let file = std::fs::File::open(file).unwrap_or_else(|e| {
|
||||||
error!("Unable to open {} for {} input: {}", file.display(), fmt, e);
|
error!("Unable to open {} for {fmt} input: {e}", file.display());
|
||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
});
|
});
|
||||||
Some(Box::new(file))
|
Some(Box::new(file))
|
||||||
|
@ -18,9 +18,9 @@ macro_rules! time_ns {
|
|||||||
let msg = $msg;
|
let msg = $msg;
|
||||||
let elapsed = start.elapsed().as_nanos();
|
let elapsed = start.elapsed().as_nanos();
|
||||||
if $timing {
|
if $timing {
|
||||||
eprintln!("{},{}", msg, elapsed);
|
eprintln!("{msg},{elapsed}");
|
||||||
} else {
|
} else {
|
||||||
info!("{} ({}ns)", msg, elapsed);
|
info!("{msg} ({elapsed}ns)");
|
||||||
}
|
}
|
||||||
v
|
v
|
||||||
}};
|
}};
|
||||||
@ -226,8 +226,8 @@ pub mod json {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
Value::Null => Node::String(Typ::Null, "".into()), // always empty
|
Value::Null => Node::String(Typ::Null, "".into()), // always empty
|
||||||
Value::Bool(b) => Node::String(Typ::Boolean, format!("{}{}", b, nl)),
|
Value::Bool(b) => Node::String(Typ::Boolean, format!("{b}{nl}")),
|
||||||
Value::Number(n) => Node::String(Typ::Float, format!("{}{}", n, nl)),
|
Value::Number(n) => Node::String(Typ::Float, format!("{n}{nl}")),
|
||||||
Value::String(s) => {
|
Value::String(s) => {
|
||||||
if config.try_decode_base64 {
|
if config.try_decode_base64 {
|
||||||
if let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(&s) {
|
if let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(&s) {
|
||||||
@ -263,7 +263,7 @@ pub mod json {
|
|||||||
} else if contents == "false" {
|
} else if contents == "false" {
|
||||||
Value::Bool(false)
|
Value::Bool(false)
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as boolean", contents);
|
debug!("string '{contents}' tagged as boolean");
|
||||||
Value::String(contents)
|
Value::String(contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,7 +273,7 @@ pub mod json {
|
|||||||
if let Ok(n) = serde_json::Number::from_str(&contents) {
|
if let Ok(n) = serde_json::Number::from_str(&contents) {
|
||||||
Value::Number(n)
|
Value::Number(n)
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as float", contents);
|
debug!("string '{contents}' tagged as float");
|
||||||
Value::String(contents)
|
Value::String(contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ pub mod json {
|
|||||||
if let Ok(n) = serde_json::Number::from_str(&contents) {
|
if let Ok(n) = serde_json::Number::from_str(&contents) {
|
||||||
Value::Number(n)
|
Value::Number(n)
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as float", contents);
|
debug!("string '{contents}' tagged as float");
|
||||||
Value::String(contents)
|
Value::String(contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,7 +289,7 @@ pub mod json {
|
|||||||
if contents.is_empty() {
|
if contents.is_empty() {
|
||||||
Value::Null
|
Value::Null
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as null", contents);
|
debug!("string '{contents}' tagged as null");
|
||||||
Value::String(contents)
|
Value::String(contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,7 +354,7 @@ pub mod toml {
|
|||||||
| Toml::Float(_)
|
| Toml::Float(_)
|
||||||
| Toml::Integer(_)
|
| Toml::Integer(_)
|
||||||
| Toml::String(_) => 1,
|
| Toml::String(_) => 1,
|
||||||
Toml::Array(vs) => vs.iter().map(|v| toml_size(v)).sum::<usize>() + 1,
|
Toml::Array(vs) => vs.iter().map(toml_size).sum::<usize>() + 1,
|
||||||
Toml::Table(fvs) => fvs.iter().map(|(_, v)| toml_size(v)).sum::<usize>() + 1,
|
Toml::Table(fvs) => fvs.iter().map(|(_, v)| toml_size(v)).sum::<usize>() + 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,10 +375,10 @@ pub mod toml {
|
|||||||
let nl = if config.add_newlines { "\n" } else { "" };
|
let nl = if config.add_newlines { "\n" } else { "" };
|
||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Toml::Boolean(b) => Node::String(Typ::Boolean, format!("{}{}", b, nl)),
|
Toml::Boolean(b) => Node::String(Typ::Boolean, format!("{b}{nl}")),
|
||||||
Toml::Datetime(s) => Node::String(Typ::Datetime, s.to_string()),
|
Toml::Datetime(s) => Node::String(Typ::Datetime, s.to_string()),
|
||||||
Toml::Float(n) => Node::String(Typ::Float, format!("{}{}", n, nl)),
|
Toml::Float(n) => Node::String(Typ::Float, format!("{n}{nl}")),
|
||||||
Toml::Integer(n) => Node::String(Typ::Integer, format!("{}{}", n, nl)),
|
Toml::Integer(n) => Node::String(Typ::Integer, format!("{n}{nl}")),
|
||||||
Toml::String(s) => {
|
Toml::String(s) => {
|
||||||
if config.try_decode_base64 {
|
if config.try_decode_base64 {
|
||||||
if let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(&s) {
|
if let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(&s) {
|
||||||
@ -418,7 +418,7 @@ pub mod toml {
|
|||||||
} else if contents == "false" {
|
} else if contents == "false" {
|
||||||
Toml::Boolean(false)
|
Toml::Boolean(false)
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as boolean", contents);
|
debug!("string '{contents}' tagged as boolean");
|
||||||
Toml::String(contents)
|
Toml::String(contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -426,10 +426,7 @@ pub mod toml {
|
|||||||
Typ::Datetime => match str::parse(&contents) {
|
Typ::Datetime => match str::parse(&contents) {
|
||||||
Ok(datetime) => Toml::Datetime(datetime),
|
Ok(datetime) => Toml::Datetime(datetime),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!(
|
debug!("string '{contents}' tagged as datetime, didn't parse: {e}");
|
||||||
"string '{}' tagged as datetime, didn't parse: {}",
|
|
||||||
contents, e
|
|
||||||
);
|
|
||||||
Toml::String(contents)
|
Toml::String(contents)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -437,7 +434,7 @@ pub mod toml {
|
|||||||
if let Ok(n) = f64::from_str(&contents) {
|
if let Ok(n) = f64::from_str(&contents) {
|
||||||
Toml::Float(n)
|
Toml::Float(n)
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as float", contents);
|
debug!("string '{contents}' tagged as float");
|
||||||
Toml::String(contents)
|
Toml::String(contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,7 +442,7 @@ pub mod toml {
|
|||||||
if let Ok(n) = i64::from_str(&contents) {
|
if let Ok(n) = i64::from_str(&contents) {
|
||||||
Toml::Integer(n)
|
Toml::Integer(n)
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as float", contents);
|
debug!("string '{contents}' tagged as float");
|
||||||
Toml::String(contents)
|
Toml::String(contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,7 +450,7 @@ pub mod toml {
|
|||||||
if contents.is_empty() {
|
if contents.is_empty() {
|
||||||
Toml::String(contents)
|
Toml::String(contents)
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as null", contents);
|
debug!("string '{contents}' tagged as null");
|
||||||
Toml::String(contents)
|
Toml::String(contents)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,18 +534,18 @@ pub mod yaml {
|
|||||||
| Yaml::Null
|
| Yaml::Null
|
||||||
| Yaml::BadValue
|
| Yaml::BadValue
|
||||||
| Yaml::Alias(_) => 1,
|
| Yaml::Alias(_) => 1,
|
||||||
Yaml::Array(vs) => vs.iter().map(|v| yaml_size(v)).sum::<usize>() + 1,
|
Yaml::Array(vs) => vs.iter().map(yaml_size).sum::<usize>() + 1,
|
||||||
Yaml::Hash(fvs) => fvs.iter().map(|(_, v)| yaml_size(v)).sum::<usize>() + 1,
|
Yaml::Hash(fvs) => fvs.iter().map(|(_, v)| yaml_size(v)).sum::<usize>() + 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn yaml_key_to_string(v: Yaml) -> String {
|
fn yaml_key_to_string(v: Yaml) -> String {
|
||||||
match v {
|
match v {
|
||||||
Yaml::Boolean(b) => format!("{}", b),
|
Yaml::Boolean(b) => format!("{b}"),
|
||||||
Yaml::Real(s) => s,
|
Yaml::Real(s) => s,
|
||||||
Yaml::Integer(n) => format!("{}", n),
|
Yaml::Integer(n) => format!("{n}"),
|
||||||
Yaml::String(s) => s,
|
Yaml::String(s) => s,
|
||||||
Yaml::Alias(n) => format!("alias{}", n),
|
Yaml::Alias(n) => format!("alias{n}"),
|
||||||
Yaml::Array(vs) => {
|
Yaml::Array(vs) => {
|
||||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||||
vs.hash(&mut hasher);
|
vs.hash(&mut hasher);
|
||||||
@ -581,9 +578,9 @@ pub mod yaml {
|
|||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Yaml::Null => Node::String(Typ::Null, "".into()),
|
Yaml::Null => Node::String(Typ::Null, "".into()),
|
||||||
Yaml::Boolean(b) => Node::String(Typ::Boolean, format!("{}{}", b, nl)),
|
Yaml::Boolean(b) => Node::String(Typ::Boolean, format!("{b}{nl}")),
|
||||||
Yaml::Real(s) => Node::String(Typ::Float, s + nl),
|
Yaml::Real(s) => Node::String(Typ::Float, s + nl),
|
||||||
Yaml::Integer(n) => Node::String(Typ::Integer, format!("{}{}", n, nl)),
|
Yaml::Integer(n) => Node::String(Typ::Integer, format!("{n}{nl}")),
|
||||||
Yaml::String(s) => {
|
Yaml::String(s) => {
|
||||||
if config.try_decode_base64 {
|
if config.try_decode_base64 {
|
||||||
if let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(&s) {
|
if let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(&s) {
|
||||||
@ -600,7 +597,7 @@ pub mod yaml {
|
|||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
// ??? 2021-06-21 support aliases w/hard links?
|
// ??? 2021-06-21 support aliases w/hard links?
|
||||||
Yaml::Alias(n) => Node::Bytes(format!("alias{}{}", n, nl).into_bytes()),
|
Yaml::Alias(n) => Node::Bytes(format!("alias{n}{nl}").into_bytes()),
|
||||||
Yaml::BadValue => Node::Bytes("bad YAML value".into()),
|
Yaml::BadValue => Node::Bytes("bad YAML value".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -628,7 +625,7 @@ pub mod yaml {
|
|||||||
} else if contents == "false" {
|
} else if contents == "false" {
|
||||||
Value(Yaml::Boolean(false))
|
Value(Yaml::Boolean(false))
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as boolean", contents);
|
debug!("string '{contents}' tagged as boolean");
|
||||||
Value(Yaml::String(contents))
|
Value(Yaml::String(contents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -638,7 +635,7 @@ pub mod yaml {
|
|||||||
if let Ok(_n) = f64::from_str(&contents) {
|
if let Ok(_n) = f64::from_str(&contents) {
|
||||||
Value(Yaml::Real(contents))
|
Value(Yaml::Real(contents))
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as float", contents);
|
debug!("string '{contents}' tagged as float");
|
||||||
Value(Yaml::String(contents))
|
Value(Yaml::String(contents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -646,7 +643,7 @@ pub mod yaml {
|
|||||||
if let Ok(n) = i64::from_str(&contents) {
|
if let Ok(n) = i64::from_str(&contents) {
|
||||||
Value(Yaml::Integer(n))
|
Value(Yaml::Integer(n))
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as float", contents);
|
debug!("string '{contents}' tagged as float");
|
||||||
Value(Yaml::String(contents))
|
Value(Yaml::String(contents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -654,7 +651,7 @@ pub mod yaml {
|
|||||||
if contents.is_empty() {
|
if contents.is_empty() {
|
||||||
Value(Yaml::Null)
|
Value(Yaml::Null)
|
||||||
} else {
|
} else {
|
||||||
debug!("string '{}' tagged as null", contents);
|
debug!("string '{contents}' tagged as null");
|
||||||
Value(Yaml::String(contents))
|
Value(Yaml::String(contents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
src/fs.rs
29
src/fs.rs
@ -167,9 +167,9 @@ where
|
|||||||
for (i, child) in vs.into_iter().enumerate() {
|
for (i, child) in vs.into_iter().enumerate() {
|
||||||
// TODO 2021-06-08 ability to add prefixes
|
// TODO 2021-06-08 ability to add prefixes
|
||||||
let name = if self.config.pad_element_names {
|
let name = if self.config.pad_element_names {
|
||||||
format!("{:0width$}", i, width = width)
|
format!("{i:0width$}")
|
||||||
} else {
|
} else {
|
||||||
format!("{}", i)
|
format!("{i}")
|
||||||
};
|
};
|
||||||
|
|
||||||
let kind = child.kind();
|
let kind = child.kind();
|
||||||
@ -216,7 +216,7 @@ where
|
|||||||
nfield
|
nfield
|
||||||
}
|
}
|
||||||
Munge::Filter => {
|
Munge::Filter => {
|
||||||
warn!("skipping '{}'", field);
|
warn!("skipping '{field}'");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,8 +234,7 @@ where
|
|||||||
);
|
);
|
||||||
let original_name = if original != nfield {
|
let original_name = if original != nfield {
|
||||||
info!(
|
info!(
|
||||||
"renamed {} to {} (inode {} with parent {})",
|
"renamed {original} to {nfield} (inode {child_id} with parent {inum})"
|
||||||
original, nfield, child_id, inum
|
|
||||||
);
|
);
|
||||||
Some(original)
|
Some(original)
|
||||||
} else {
|
} else {
|
||||||
@ -281,8 +280,7 @@ where
|
|||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
while !worklist.is_empty() {
|
while let Some(node) = worklist.pop() {
|
||||||
let node = worklist.pop().unwrap();
|
|
||||||
if let Some(nodes) = self.resolve_node(node)? {
|
if let Some(nodes) = self.resolve_node(node)? {
|
||||||
worklist.extend(nodes);
|
worklist.extend(nodes);
|
||||||
}
|
}
|
||||||
@ -353,7 +351,7 @@ where
|
|||||||
|
|
||||||
let v = time_ns!("reading", V::from_reader(reader), config.timing);
|
let v = time_ns!("reading", V::from_reader(reader), config.timing);
|
||||||
if v.kind() != FileType::Directory {
|
if v.kind() != FileType::Directory {
|
||||||
error!("The root of the filesystem must be a directory, but '{}' only generates a single file.", v);
|
error!("The root of the filesystem must be a directory, but '{v}' only generates a single file.");
|
||||||
std::process::exit(ERROR_STATUS_FUSE);
|
std::process::exit(ERROR_STATUS_FUSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +511,7 @@ where
|
|||||||
files.sort_unstable_by(|(name1, _), (name2, _)| name1.cmp(name2));
|
files.sort_unstable_by(|(name1, _), (name2, _)| name1.cmp(name2));
|
||||||
for (name, DirEntry { inum, .. }) in files.iter() {
|
for (name, DirEntry { inum, .. }) in files.iter() {
|
||||||
if self.config.ignored_file(name) {
|
if self.config.ignored_file(name) {
|
||||||
warn!("skipping ignored file '{}'", name);
|
warn!("skipping ignored file '{name}'");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let v = self.as_value(*inum);
|
let v = self.as_value(*inum);
|
||||||
@ -533,7 +531,7 @@ where
|
|||||||
) in files.iter()
|
) in files.iter()
|
||||||
{
|
{
|
||||||
if self.config.ignored_file(name) {
|
if self.config.ignored_file(name) {
|
||||||
warn!("skipping ignored file '{}'", name);
|
warn!("skipping ignored file '{name}'");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let v = self.as_value(*inum);
|
let v = self.as_value(*inum);
|
||||||
@ -577,7 +575,7 @@ where
|
|||||||
files.sort_unstable_by(|(name1, _), (name2, _)| name1.cmp(name2));
|
files.sort_unstable_by(|(name1, _), (name2, _)| name1.cmp(name2));
|
||||||
for (name, inum) in files {
|
for (name, inum) in files {
|
||||||
if self.config.ignored_file(&name) {
|
if self.config.ignored_file(&name) {
|
||||||
warn!("skipping ignored file '{}'", name);
|
warn!("skipping ignored file '{name}'");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let v = self.as_other_value(inum);
|
let v = self.as_other_value(inum);
|
||||||
@ -594,7 +592,7 @@ where
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
for (name, inum, original_name) in files.iter() {
|
for (name, inum, original_name) in files.iter() {
|
||||||
if self.config.ignored_file(name) {
|
if self.config.ignored_file(name) {
|
||||||
warn!("skipping ignored file '{}'", name);
|
warn!("skipping ignored file '{name}'");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let v = self.as_other_value(*inum);
|
let v = self.as_other_value(*inum);
|
||||||
@ -1001,7 +999,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(size) = size {
|
if let Some(size) = size {
|
||||||
info!("truncate() to {}", size);
|
info!("truncate() to {size}");
|
||||||
|
|
||||||
match self.get_mut(ino) {
|
match self.get_mut(ino) {
|
||||||
Ok(inode) => match &mut inode.entry {
|
Ok(inode) => match &mut inode.entry {
|
||||||
@ -1286,7 +1284,6 @@ where
|
|||||||
for (i, entry) in dot_entries
|
for (i, entry) in dot_entries
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(entries)
|
.chain(entries)
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.skip(offset as usize)
|
.skip(offset as usize)
|
||||||
{
|
{
|
||||||
@ -1338,7 +1335,7 @@ where
|
|||||||
|
|
||||||
// make sure we have a good file type
|
// make sure we have a good file type
|
||||||
let file_type = mode & libc::S_IFMT as u32;
|
let file_type = mode & libc::S_IFMT as u32;
|
||||||
if !vec![libc::S_IFREG as u32, libc::S_IFDIR as u32].contains(&file_type) {
|
if ![libc::S_IFREG as u32, libc::S_IFDIR as u32].contains(&file_type) {
|
||||||
warn!(
|
warn!(
|
||||||
"mknod only supports regular files and directories; got {:o}",
|
"mknod only supports regular files and directories; got {:o}",
|
||||||
mode
|
mode
|
||||||
@ -1894,7 +1891,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
// extend the vector
|
// extend the vector
|
||||||
let extra_bytes = (offset + length as i64) - contents.len() as i64;
|
let extra_bytes = (offset + length) - contents.len() as i64;
|
||||||
if extra_bytes > 0 {
|
if extra_bytes > 0 {
|
||||||
contents.resize(contents.len() + extra_bytes as usize, 0);
|
contents.resize(contents.len() + extra_bytes as usize, 0);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user