Skip to content

Commit

Permalink
implement preserver-ownership flag
Browse files Browse the repository at this point in the history
  • Loading branch information
muhamadazmy committed Sep 22, 2023
1 parent 94d38fb commit f27801f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 13 deletions.
17 changes: 13 additions & 4 deletions src/cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,19 @@ where
/// get a file block either from cache or from remote if it's already
/// not cached
pub async fn get(&self, block: &Block) -> Result<(u64, File)> {
let mut file = self.prepare(&block.id).await?;
let mut file = self
.prepare(&block.id)
.await
.context("failed to prepare cache block")?;
// TODO: locking must happen here so no
// other processes start downloading the same chunk
let locker = Locker::new(&file);
locker.lock().await?;

let meta = file.metadata().await?;
let meta = file
.metadata()
.await
.context("failed to get block metadata")?;
if meta.len() > 0 {
// chunk is already downloaded
debug!("block cache hit: {}", block.id.as_slice().hex());
Expand All @@ -74,7 +80,10 @@ where
}

debug!("downloading block: {}", block.id.as_slice().hex());
let size = self.download(&mut file, block).await?;
let size = self
.download(&mut file, block)
.await
.context("failed to download block")?;

// if file is just downloaded, we need
// to seek to beginning of the file.
Expand All @@ -92,7 +101,7 @@ where
let (_, mut chunk) = self.get(block).await?;
copy(&mut chunk, out)
.await
.with_context(|| format!("failed to download block {}", index))?;
.with_context(|| format!("failed to copy block {}", index))?;
}

Ok(())
Expand Down
45 changes: 37 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ extern crate log;
use anyhow::Context;
use fungi::meta::Ino;
use fungi::Writer;
use nix::unistd::{fchownat, FchownatFlags, Gid, Uid};
use std::collections::LinkedList;
use std::ffi::OsString;
use std::fs::Metadata;
Expand All @@ -29,6 +30,7 @@ struct CopyVisitor<'a, S>
where
S: store::Store,
{
preserve: bool,
meta: &'a fungi::Reader,
cache: &'a cache::Cache<S>,
root: &'a Path,
Expand All @@ -38,8 +40,18 @@ impl<'a, S> CopyVisitor<'a, S>
where
S: store::Store,
{
pub fn new(meta: &'a fungi::Reader, cache: &'a Cache<S>, root: &'a Path) -> Self {
Self { meta, cache, root }
pub fn new(
meta: &'a fungi::Reader,
cache: &'a Cache<S>,
root: &'a Path,
preserve: bool,
) -> Self {
Self {
meta,
cache,
root,
preserve,
}
}
}

Expand All @@ -49,6 +61,8 @@ where
S: Store,
{
async fn visit(&mut self, path: &Path, node: &Inode) -> Result<Walk> {
use std::fs::Permissions;
use std::os::unix::fs::PermissionsExt;
use tokio::fs::OpenOptions;

let rooted = self.root.join(path.strip_prefix("/").unwrap());
Expand All @@ -60,10 +74,9 @@ where
}
FileType::Regular => {
let mut fd = OpenOptions::new()
.create(true)
.create_new(true)
.write(true)
.truncate(true)
.mode(node.mode.mode())
.open(&rooted)
.await
.with_context(|| format!("failed to create file '{:?}'", rooted))?;
Expand All @@ -72,7 +85,10 @@ where
self.cache
.direct(&blocks, &mut fd)
.await
.with_context(|| format!("failed to create download file '{:?}'", rooted))?;
.with_context(|| format!("failed to download file '{:?}'", rooted))?;

fd.set_permissions(Permissions::from_mode(node.mode.mode()))
.await?;
}
FileType::Link => {
let target = node
Expand All @@ -91,10 +107,22 @@ where
.with_context(|| format!("failed to create symlink '{:?}'", rooted))?;
}
_ => {
debug!("unknown file kind: {:?}", node.mode.file_type());
warn!("unknown file kind: {:?}", node.mode.file_type());
return Ok(Walk::Continue);
}
};

if self.preserve {
fchownat(
None,
&rooted,
Some(Uid::from_raw(node.uid)),
Some(Gid::from_raw(node.gid)),
FchownatFlags::NoFollowSymlink,
)
.with_context(|| format!("failed to change ownership of '{:?}'", &rooted))?;
}

Ok(Walk::Continue)
}
}
Expand All @@ -105,8 +133,9 @@ pub async fn unpack<P: AsRef<Path>, S: Store>(
meta: &Reader,
cache: &Cache<S>,
root: P,
preserve: bool,
) -> Result<()> {
let mut visitor = CopyVisitor::new(meta, cache, root.as_ref());
let mut visitor = CopyVisitor::new(meta, cache, root.as_ref(), preserve);

meta.walk(&mut visitor).await
}
Expand Down Expand Up @@ -333,7 +362,7 @@ mod test {
assert_eq!((routers[0].start, routers[0].end), (0x00, 0x7f));
assert_eq!((routers[1].start, routers[1].end), (0x80, 0xff));

unpack(&reader, &cache, root.join("destination"))
unpack(&reader, &cache, root.join("destination"), false)
.await
.unwrap();

Expand Down
7 changes: 6 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ struct UnpackOptions {
#[clap(short, long, default_value_t = String::from("/tmp/cache"))]
cache: String,

/// preserve files ownership from the FL, otherwise use the current user ownership
/// setting this flag to true normally requires sudo
#[clap(short, long, default_value_t = false)]
preserve_ownership: bool,

/// target directory to upload
target: String,
}
Expand Down Expand Up @@ -132,7 +137,7 @@ fn unpack(opts: UnpackOptions) -> Result<()> {
let router = get_router(&meta).await?;

let cache = cache::Cache::new(opts.cache, router);
rfs::unpack(&meta, &cache, opts.target).await?;
rfs::unpack(&meta, &cache, opts.target, opts.preserve_ownership).await?;
Ok(())
})
}
Expand Down

0 comments on commit f27801f

Please sign in to comment.