summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2021-02-19 20:19:15 +0200
committerLars Wirzenius <liw@liw.fi>2021-02-19 20:19:15 +0200
commitff17410cbee1492a5ca87869f76a2dafb7f90430 (patch)
tree0266517f6efc8027c5c58c7634de5e7176ee1a64
parent248e5ab7518746c0ac43747040290e9b5d138028 (diff)
downloadobnam2-ff17410cbee1492a5ca87869f76a2dafb7f90430.tar.gz
feat: backup and restore named pipes (FIFOs)
-rw-r--r--obnam.md6
-rw-r--r--src/client.rs1
-rw-r--r--src/cmd/list_files.rs1
-rw-r--r--src/cmd/restore.rs18
-rw-r--r--src/fsentry.rs6
-rw-r--r--subplot/data.py4
-rw-r--r--subplot/data.yaml3
7 files changed, 37 insertions, 2 deletions
diff --git a/obnam.md b/obnam.md
index e386b17..240dcf0 100644
--- a/obnam.md
+++ b/obnam.md
@@ -1286,7 +1286,10 @@ then command fails
## Irregular files
This scenario verifies that Obnam backs up and restores files that
-aren't regular files or directories.
+aren't regular files, directories, or symbolic links. Specifically,
+Unix domain sockets and named pipes (FIFOs). However, block and
+character device nodes are not tested, as that would require running
+the test suite with `root` permissions and that would be awkward.
~~~scenario
given an installed obnam
@@ -1294,6 +1297,7 @@ and a running chunk server
and a client config based on smoke.yaml
and a file live/data.dat containing some random data
and a Unix socket live/socket
+and a named pipe live/pipe
and a manifest of the directory live in live.yaml
when I run obnam --config smoke.yaml backup
when I invoke obnam --config smoke.yaml restore latest rest
diff --git a/src/client.rs b/src/client.rs
index 9d1e8ff..7d1613c 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -164,6 +164,7 @@ impl BackupClient {
FilesystemKind::Directory => vec![],
FilesystemKind::Symlink => vec![],
FilesystemKind::Socket => vec![],
+ FilesystemKind::Fifo => vec![],
};
info!("upload OK for {:?}", path);
Ok(ids)
diff --git a/src/cmd/list_files.rs b/src/cmd/list_files.rs
index 4982cc2..ec3e52e 100644
--- a/src/cmd/list_files.rs
+++ b/src/cmd/list_files.rs
@@ -36,6 +36,7 @@ fn format_entry(e: &FilesystemEntry, reason: Reason) -> String {
FilesystemKind::Directory => "d",
FilesystemKind::Symlink => "l",
FilesystemKind::Socket => "s",
+ FilesystemKind::Fifo => "p",
};
format!("{} {} ({})", kind, e.pathbuf().display(), reason)
}
diff --git a/src/cmd/restore.rs b/src/cmd/restore.rs
index 147a56b..b394d7d 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, timespec, utimensat, AT_FDCWD};
+use libc::{chmod, mkfifo, timespec, utimensat, AT_FDCWD};
use log::{debug, error, info};
use std::ffi::CString;
use std::io::prelude::*;
@@ -73,6 +73,9 @@ struct Opt {
#[derive(Debug, thiserror::Error)]
pub enum RestoreError {
+ #[error("Could not create named pipe (FIFO) {0}")]
+ NamedPipeCreationError(PathBuf),
+
#[error(transparent)]
ClientError(#[from] ClientError),
@@ -112,6 +115,7 @@ fn restore_generation(
FilesystemKind::Directory => restore_directory(&to)?,
FilesystemKind::Symlink => restore_symlink(&to, &entry)?,
FilesystemKind::Socket => restore_socket(&to, &entry)?,
+ FilesystemKind::Fifo => restore_fifo(&to, &entry)?,
}
Ok(())
}
@@ -188,6 +192,18 @@ fn restore_socket(path: &Path, entry: &FilesystemEntry) -> RestoreResult<()> {
Ok(())
}
+fn restore_fifo(path: &Path, entry: &FilesystemEntry) -> RestoreResult<()> {
+ debug!("creating fifo {:?}", path);
+ let filename = path_to_cstring(path);
+ match unsafe { mkfifo(filename.as_ptr(), 0) } {
+ -1 => {
+ return Err(RestoreError::NamedPipeCreationError(path.to_path_buf()));
+ }
+ _ => restore_metadata(path, entry)?,
+ }
+ Ok(())
+}
+
fn restore_metadata(path: &Path, entry: &FilesystemEntry) -> RestoreResult<()> {
debug!("restoring metadata for {}", entry.pathbuf().display());
diff --git a/src/fsentry.rs b/src/fsentry.rs
index 9384ec6..570877a 100644
--- a/src/fsentry.rs
+++ b/src/fsentry.rs
@@ -129,6 +129,7 @@ pub enum FilesystemKind {
Directory,
Symlink,
Socket,
+ Fifo,
}
impl FilesystemKind {
@@ -141,6 +142,8 @@ impl FilesystemKind {
FilesystemKind::Symlink
} else if file_type.is_socket() {
FilesystemKind::Socket
+ } else if file_type.is_fifo() {
+ FilesystemKind::Fifo
} else {
panic!("unknown file type {:?}", file_type);
}
@@ -152,6 +155,7 @@ impl FilesystemKind {
FilesystemKind::Directory => 1,
FilesystemKind::Symlink => 2,
FilesystemKind::Socket => 3,
+ FilesystemKind::Fifo => 4,
}
}
@@ -161,6 +165,7 @@ impl FilesystemKind {
1 => Ok(FilesystemKind::Directory),
2 => Ok(FilesystemKind::Symlink),
3 => Ok(FilesystemKind::Socket),
+ 4 => Ok(FilesystemKind::Fifo),
_ => Err(FsEntryError::UnknownFileKindCode(code).into()),
}
}
@@ -182,6 +187,7 @@ mod test {
one_file_kind_round_trip(FilesystemKind::Directory);
one_file_kind_round_trip(FilesystemKind::Symlink);
one_file_kind_round_trip(FilesystemKind::Socket);
+ one_file_kind_round_trip(FilesystemKind::Fifo);
}
fn one_file_kind_round_trip(kind: FilesystemKind) {
diff --git a/subplot/data.py b/subplot/data.py
index 3c369d1..0c1a4a5 100644
--- a/subplot/data.py
+++ b/subplot/data.py
@@ -24,6 +24,10 @@ def create_unix_socket(ctx, filename=None):
fd.bind(filename)
+def create_fifo(ctx, filename=None):
+ os.mkfifo(filename)
+
+
def create_nonutf8_filename(ctx, dirname=None):
filename = "\x88"
os.mkdir(dirname)
diff --git a/subplot/data.yaml b/subplot/data.yaml
index 97e6eed..0e13abd 100644
--- a/subplot/data.yaml
+++ b/subplot/data.yaml
@@ -7,6 +7,9 @@
- given: "a Unix socket {filename}"
function: create_unix_socket
+- given: "a named pipe {filename}"
+ function: create_fifo
+
- given: "a file in {dirname} with a non-UTF8 filename"
function: create_nonutf8_filename