Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/cli/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,11 @@ pub async fn run(config: &Config, cache: Option<&Cache>, args: Args) -> crate::R
if let Err(err) = track_collection.write_tags() {
log::error!("Failed to write tags: {err}");
}

#[cfg(unix)]
if let Err(err) = track_collection.set_permissions(&cloned_config) {
log::error!("Failed to set permissions: {err}");
}
}
});

Expand Down
18 changes: 18 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,20 @@ pub struct PathTemplateConfig {
pub compilation_format: String,
}

/// The import configuration struct.
#[cfg(unix)]
#[expect(missing_copy_implementations)]
#[expect(clippy::struct_field_names)]
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
pub struct ImportConfig {
/// User ID to set.
pub set_uid: Option<u32>,
/// Group ID to set.
pub set_gid: Option<u32>,
/// File mode to set.
pub set_mode: Option<u32>,
}

/// The main configuration struct.
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Config {
Expand All @@ -392,6 +406,10 @@ pub struct Config {
pub weights: DistanceWeights,
/// UI configuration.
pub user_interface: UiConfig,
/// Import configuration.
#[cfg(unix)]
#[serde(default)]
pub import: ImportConfig,
}

impl Default for Config {
Expand Down
23 changes: 23 additions & 0 deletions src/taggedfilecollection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,29 @@ impl TaggedFileCollection {

Ok(())
}

/// Set permission for all tracks in this collection.
///
/// # Errors
///
/// Returns an error if any of the underlying file system operations fail.
#[cfg(unix)]
pub fn set_permissions(&mut self, config: &Config) -> crate::Result<()> {
for track in &mut self
.media
.iter_mut()
.flat_map(|media| media.tracks.iter_mut())
{
util::set_file_permissions(
&track.path,
config.import.set_uid,
config.import.set_gid,
config.import.set_mode,
)?;
}

Ok(())
}
}

impl IntoIterator for TaggedFileCollection {
Expand Down
47 changes: 46 additions & 1 deletion src/util/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ use std::collections::BinaryHeap;
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::os::unix::{self, fs::PermissionsExt};
use std::path::{Path, PathBuf};

/// An iterator that recursively walks through a directory structure and yields a tuple `(path,
/// dirs, files)` for each directory it visits.
///
/// This struct is created by [`walk_dir`]. See its documentation for more.
pub struct DirWalk {
/// Queued paths that will be visited next.
Expand Down Expand Up @@ -117,3 +117,48 @@ pub fn move_file<S: AsRef<Path>, D: AsRef<Path>>(source: S, destination: D) -> c

Ok(())
}

/// Set file/directory owner and permissions.
#[cfg(unix)]
pub fn set_file_permissions<S: AsRef<Path>>(
source: S,
uid: Option<u32>,
gid: Option<u32>,
mode: Option<u32>,
) -> crate::Result<()> {
let path = source.as_ref();

unix::fs::chown(path, uid, gid)?;
match (uid, gid) {
(Some(owner), Some(group)) => {
log::info!(
"Changed owner/group for {} to {owner}:{group}.",
path.display()
);
}
(Some(owner), None) => {
log::info!("Changed owner for {} to {owner}.", path.display());
}
(None, Some(group)) => {
log::info!("Changed group for {} to {group}.", path.display());
}
_ => (),
}

if let Some(new_mode) = mode {
let metadata = fs::metadata(path)?;
let permissions = metadata.permissions();
let old_mode = permissions.mode();

if permissions.mode() != new_mode {
let permissions = fs::Permissions::from_mode(new_mode);
fs::set_permissions(path, permissions)?; // ← Works on paths (files & directories)
log::info!(
"Permission for {} changed from {old_mode:o} to {new_mode:o}.",
path.display()
);
}
}

Ok(())
}
2 changes: 2 additions & 0 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ mod keyed_binheap;
mod testing;
mod time;

#[cfg(unix)]
pub use fs::set_file_permissions;
pub use fs::{move_file, walk_dir};
pub use keyed_binheap::KeyedBinaryHeap;
#[cfg(any(test, feature = "dev"))]
Expand Down
Loading