diff options
author | Alexander Batischev <eual.jp@gmail.com> | 2021-06-13 01:45:02 +0300 |
---|---|---|
committer | Alexander Batischev <eual.jp@gmail.com> | 2021-06-13 01:45:02 +0300 |
commit | 8641c594b0d065f5000efd84d30333c2762ef74c (patch) | |
tree | ef554b000ef98a5556d31cc4276763cee10a0a2d /src/cmd | |
parent | 481c5d8df21c72db3a3d76e851d25426f3e40647 (diff) | |
download | obnam2-8641c594b0d065f5000efd84d30333c2762ef74c.tar.gz |
feat: restore symlink metadata
The weird thing about this commit is that all the tests for it already
exist: the subplot compares manifests of "live" and restored data, and
that includes the mtime. The subplot passes on CI, and it passed for me
too — until today.
Today, if I run `./check` on the main branch (which is currently at
481c5d8df21c72db3a3d76e851d25426f3e40647), subplot fails because the
symlinks' mtime is wrong. Most often it's just the nsec part that's
wrong: tests run fast enough that they finish within a second, and they
rarely happen at the edge of the second.
I don't understand why this didn't happen to me before, and why it
doesn't happen to CI — and to Lars, for that matter. git-bisect points
at 755c18a11f87040245964cf411ea8f518b61e0f5, which is a couple months
old, so we should've spotted the breakage by now.
Needless to say, I didn't do any major overhauls of my system lately,
just your usual `apt upgrade` (Debian bullseye/testing amd64). Did some
change in Subplot or Summain obfuscate this? It bothers me that I don't
understand how we could miss this for so long.
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/restore.rs | 21 |
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)); |