summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2021-06-19 06:36:45 +0000
committerLars Wirzenius <liw@liw.fi>2021-06-19 06:36:45 +0000
commit0536ceaf7ae28d9b0db36b58719d74c58518f949 (patch)
tree692540106c42632b16a42349650fac060ea44062
parentace5bd80bbac17c6a913dbe58dd80505afee678c (diff)
parent8641c594b0d065f5000efd84d30333c2762ef74c (diff)
downloadobnam2-0536ceaf7ae28d9b0db36b58719d74c58518f949.tar.gz
Merge branch 'feature/restore-symlink-metadata' into 'main'
feat: restore symlink metadata See merge request obnam/obnam!154
-rw-r--r--src/cmd/restore.rs21
1 files changed, 14 insertions, 7 deletions
diff --git a/src/cmd/restore.rs b/src/cmd/restore.rs
index 01e96bf..3c5b896 100644
--- a/src/cmd/restore.rs
+++ b/src/cmd/restore.rs
@@ -5,7 +5,7 @@ use crate::error::ObnamError;
use crate::fsentry::{FilesystemEntry, FilesystemKind};
use crate::generation::{LocalGeneration, LocalGenerationError};
use indicatif::{ProgressBar, ProgressStyle};
-use libc::{chmod, mkfifo, timespec, utimensat, AT_FDCWD};
+use libc::{chmod, mkfifo, timespec, utimensat, AT_FDCWD, AT_SYMLINK_NOFOLLOW};
use log::{debug, error, info};
use std::ffi::CString;
use std::io::prelude::*;
@@ -209,6 +209,7 @@ fn restore_symlink(path: &Path, entry: &FilesystemEntry) -> RestoreResult<()> {
}
symlink(entry.symlink_target().unwrap(), path)
.map_err(|err| RestoreError::Symlink(path.to_path_buf(), err))?;
+ restore_metadata(path, entry)?;
debug!("restored symlink {}", path.display());
Ok(())
}
@@ -254,15 +255,21 @@ fn restore_metadata(path: &Path, entry: &FilesystemEntry) -> RestoreResult<()> {
// We have to use unsafe here to be able call the libc functions
// below.
unsafe {
- debug!("chmod {:?}", path);
- if chmod(path.as_ptr(), entry.mode()) == -1 {
- let error = Error::last_os_error();
- error!("chmod failed on {:?}", path);
- return Err(RestoreError::Chmod(pathbuf, error));
+ if entry.kind() != FilesystemKind::Symlink {
+ debug!("chmod {:?}", path);
+ if chmod(path.as_ptr(), entry.mode()) == -1 {
+ let error = Error::last_os_error();
+ error!("chmod failed on {:?}", path);
+ return Err(RestoreError::Chmod(pathbuf, error));
+ }
+ } else {
+ debug!(
+ "skipping chmod of a symlink because it'll attempt to change the pointed-at file"
+ );
}
debug!("utimens {:?}", path);
- if utimensat(AT_FDCWD, path.as_ptr(), times, 0) == -1 {
+ if utimensat(AT_FDCWD, path.as_ptr(), times, AT_SYMLINK_NOFOLLOW) == -1 {
let error = Error::last_os_error();
error!("utimensat failed on {:?}", path);
return Err(RestoreError::SetTimestamp(pathbuf, error));