Skip to content
Open
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
59 changes: 55 additions & 4 deletions src/uucore/src/lib/features/fsxattr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,16 +235,21 @@ pub fn apply_xattrs_fd(
Ok(())
}

/// Like [`apply_xattrs_fd`], but maps `ENOTSUP` / `EOPNOTSUPP` to `Ok(())`.
/// Like [`apply_xattrs_fd`], but skips unsupported attributes.
#[cfg(unix)]
pub fn apply_xattrs_fd_ignore_unsupported(
dest: &std::fs::File,
xattrs: FxHashMap<OsString, Vec<u8>>,
) -> std::io::Result<()> {
match apply_xattrs_fd(dest, xattrs) {
Err(e) if is_xattr_unsupported(&e) => Ok(()),
res => res,
use xattr::FileExt;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a test, a unit test here is enough:
an unknown namespace like foo.x gets EOPNOTSUPP from the kernel, so apply it with a few user.* and check those are set

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the doc comment above still says it maps ENOTSUP to Ok(()), please update it to say it skips the unsupported attributes

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

for (attr, value) in xattrs {
match dest.set_xattr(&attr, &value) {
Err(e) if is_xattr_unsupported(&e) => {}
Err(e) => return Err(e),
Ok(()) => {}
}
}
Ok(())
}

/// Checks if a file has an Access Control List (ACL).
Expand Down Expand Up @@ -610,4 +615,50 @@ mod tests {
test_value
);
}

#[test]
#[cfg(target_os = "linux")]
fn test_apply_xattrs_fd_ignore_unsupported() {
let temp_dir = tempdir().unwrap();
let file_path = temp_dir.path().join("test_file.txt");

File::create(&file_path).unwrap();

// Skip silently if the test fs doesn't support user xattrs.
if xattr::set(&file_path, "user.probe", b"probe").is_err() {
return;
}
xattr::remove(&file_path, "user.probe").unwrap();

// Names in an unknown namespace get EOPNOTSUPP from the kernel.
let unsupported = ["foo.x", "bar.x", "baz.x"];
for name in unsupported {
let err = xattr::set(&file_path, name, b"unsupported").unwrap_err();
assert!(is_xattr_unsupported(&err));
}

let supported = ["user.a", "user.b", "user.c", "user.d", "user.e"];

let mut test_xattrs = FxHashMap::default();
for name in unsupported {
test_xattrs.insert(OsString::from(name), b"unsupported".to_vec());
}
for name in supported {
test_xattrs.insert(OsString::from(name), name.as_bytes().to_vec());
}

let dest = std::fs::OpenOptions::new()
.write(true)
.open(&file_path)
.unwrap();

apply_xattrs_fd_ignore_unsupported(&dest, test_xattrs).unwrap();

for name in supported {
assert_eq!(
xattr::get(&file_path, name).unwrap().unwrap(),
name.as_bytes()
);
}
}
}