Skip to content
Snippets Groups Projects
Verified Commit 900f77e7 authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Use pkgar_head files for installer_tui

parent adebf727
No related branches found
No related tags found
No related merge requests found
extern crate arg_parser; extern crate arg_parser;
#[macro_use] extern crate failure;
extern crate pkgar;
extern crate pkgar_core;
extern crate pkgar_keys;
extern crate redox_installer; extern crate redox_installer;
extern crate serde; extern crate serde;
extern crate termion; extern crate termion;
extern crate toml; extern crate toml;
use pkgar::{PackageHead, ext::EntryExt};
use pkgar_core::PackageSrc;
use pkgar_keys::PublicKeyFile;
use redox_installer::{Config, with_redoxfs}; use redox_installer::{Config, with_redoxfs};
use std::{fs, io, process}; use std::{
ffi::OsStr,
fs,
io::{self, Read, Write},
os::unix::fs::{MetadataExt, OpenOptionsExt, symlink},
path::Path,
process
};
use termion::input::TermRead; use termion::input::TermRead;
#[cfg(not(target_os = "redox"))] #[cfg(not(target_os = "redox"))]
...@@ -76,24 +90,106 @@ fn format_size(size: u64) -> String { ...@@ -76,24 +90,106 @@ fn format_size(size: u64) -> String {
} }
} }
fn dir_files(dir: &str, files: &mut Vec<String>) -> io::Result<()> { fn copy_file(src: &Path, dest: &Path, buf: &mut [u8]) -> Result<(), failure::Error> {
for entry_res in fs::read_dir(&format!("file:/{}", dir))? { if let Some(parent) = dest.parent() {
let entry = entry_res?; match fs::create_dir_all(&parent) {
let path = entry.path(); Ok(()) => (),
let path_str = path.into_os_string().into_string().map_err(|_| { Err(err) => {
io::Error::new( return Err(format_err!("failed to create directory {}: {}", parent.display(), err));
io::ErrorKind::InvalidData, }
"Failed to convert Path to &str"
)
})?;
let path_trimmed = path_str.trim_start_matches("file:/");
let metadata = entry.metadata()?;
if metadata.is_dir() {
dir_files(path_trimmed, files)?;
} else {
files.push(path_trimmed.to_string());
} }
} }
let metadata = match fs::symlink_metadata(&src) {
Ok(ok) => ok,
Err(err) => {
return Err(format_err!("failed to read metadata of {}: {}", src.display(), err));
},
};
if metadata.file_type().is_symlink() {
let real_src = match fs::read_link(&src) {
Ok(ok) => ok,
Err(err) => {
return Err(format_err!("failed to read link {}: {}", src.display(), err));
}
};
match symlink(&real_src, &dest) {
Ok(()) => (),
Err(err) => {
return Err(format_err!("failed to copy link {} ({}) to {}: {}", src.display(), real_src.display(), dest.display(), err));
},
}
} else {
let mut src_file = match fs::File::open(&src) {
Ok(ok) => ok,
Err(err) => {
return Err(format_err!("failed to open file {}: {}", src.display(), err));
}
};
let mut dest_file = match fs::OpenOptions::new().write(true).create_new(true).mode(metadata.mode()).open(&dest) {
Ok(ok) => ok,
Err(err) => {
return Err(format_err!("failed to create file {}: {}", dest.display(), err));
}
};
loop {
let count = match src_file.read(buf) {
Ok(ok) => ok,
Err(err) => {
return Err(format_err!("failed to read file {}: {}", src.display(), err));
}
};
if count == 0 {
break;
}
match dest_file.write_all(&buf[..count]) {
Ok(()) => (),
Err(err) => {
return Err(format_err!("failed to write file {}: {}", dest.display(), err));
}
}
}
}
Ok(())
}
fn package_files(root_path: &Path, config: &mut Config, files: &mut Vec<String>) -> Result<(), pkgar::Error> {
//TODO: Remove packages from config where all files are located (and have valid shasum?)
config.packages.clear();
let pkey_path = "pkg/id_ed25519.pub.toml";
let pkey = PublicKeyFile::open(&root_path.join(pkey_path))?.pkey;
files.push(pkey_path.to_string());
for item_res in fs::read_dir(&root_path.join("pkg"))? {
let item = item_res?;
let pkg_path = item.path();
if pkg_path.extension() == Some(OsStr::new("pkgar_head")) {
let mut pkg = PackageHead::new(&pkg_path, &root_path, &pkey)?;
for entry in pkg.read_entries()? {
files.push(
entry
.check_path()?
.to_str().unwrap()
.to_string()
);
}
files.push(
pkg_path
.strip_prefix(root_path).unwrap()
.to_str().unwrap()
.to_string()
);
}
}
Ok(()) Ok(())
} }
...@@ -158,16 +254,18 @@ fn choose_password() -> Option<String> { ...@@ -158,16 +254,18 @@ fn choose_password() -> Option<String> {
} }
fn main() { fn main() {
let root_path = Path::new("file:");
let disk_path = choose_disk(); let disk_path = choose_disk();
let password_opt = choose_password(); let password_opt = choose_password();
let bootloader = { let bootloader = {
let path = "file:/bootloader"; let path = root_path.join("bootloader");
let mut bootloader = match fs::read(path) { let mut bootloader = match fs::read(&path) {
Ok(ok) => ok, Ok(ok) => ok,
Err(err) => { Err(err) => {
eprintln!("installer_tui: {}: failed to read: {}", path, err); eprintln!("installer_tui: {}: failed to read: {}", path.display(), err);
process::exit(1); process::exit(1);
} }
}; };
...@@ -182,26 +280,20 @@ fn main() { ...@@ -182,26 +280,20 @@ fn main() {
let res = with_redoxfs(&disk_path, password_opt.as_ref().map(|x| x.as_bytes()), &bootloader, |mount_path| -> Result<(), failure::Error> { let res = with_redoxfs(&disk_path, password_opt.as_ref().map(|x| x.as_bytes()), &bootloader, |mount_path| -> Result<(), failure::Error> {
let mut config: Config = { let mut config: Config = {
let path = "file:/filesystem.toml"; let path = root_path.join("filesystem.toml");
match fs::read_to_string(path) { match fs::read_to_string(&path) {
Ok(config_data) => { Ok(config_data) => {
match toml::from_str(&config_data) { match toml::from_str(&config_data) {
Ok(config) => { Ok(config) => {
config config
}, },
Err(err) => { Err(err) => {
eprintln!("installer_tui: {}: failed to decode: {}", path, err); return Err(format_err!("{}: failed to decode: {}", path.display(), err));
return Err(failure::Error::from_boxed_compat(
Box::new(err))
);
} }
} }
}, },
Err(err) => { Err(err) => {
eprintln!("installer_tui: {}: failed to read: {}", path, err); return Err(format_err!("{}: failed to read: {}", path.display(), err));
return Err(failure::Error::from_boxed_compat(
Box::new(err))
);
} }
} }
}; };
...@@ -213,55 +305,22 @@ fn main() { ...@@ -213,55 +305,22 @@ fn main() {
"kernel".to_string() "kernel".to_string()
]; ];
// Copy files from known directories // Copy files from locally installed packages
//TODO: Use package data if let Err(err) = package_files(&root_path, &mut config, &mut files) {
for dir in [ return Err(format_err!("failed to read package files: {}", err));
"bin",
"etc",
"include",
"lib",
"pkg",
"share",
"ssl",
"ui"
].iter() {
if let Err(err) = dir_files(dir, &mut files) {
eprintln!("installer_tui: failed to read files from {}: {}", dir, err);
return Err(failure::Error::from_boxed_compat(
Box::new(err))
);
}
} }
// Packages are copied by previous code // Sort and remove duplicates
config.packages.clear(); files.sort();
files.dedup();
let mut buf = vec![0; 4 * 1024 * 1024];
for (i, name) in files.iter().enumerate() { for (i, name) in files.iter().enumerate() {
eprintln!("copy {} [{}/{}]", name, i, files.len()); eprintln!("copy {} [{}/{}]", name, i, files.len());
let src = format!("file:/{}", name); let src = root_path.join(name);
let dest = mount_path.join(name); let dest = mount_path.join(name);
if let Some(parent) = dest.parent() { copy_file(&src, &dest, &mut buf)?;
match fs::create_dir_all(&parent) {
Ok(()) => (),
Err(err) => {
eprintln!("installer_tui: failed to create directory {}: {}", parent.display(), err);
return Err(failure::Error::from_boxed_compat(
Box::new(err))
);
}
}
}
match fs::copy(&src, &dest) {
Ok(_) => (),
Err(err) => {
eprintln!("installer_tui: failed to copy file {} to {}: {}", src, dest.display(), err);
return Err(failure::Error::from_boxed_compat(
Box::new(err))
);
}
}
} }
eprintln!("finished copying {} files", files.len()); eprintln!("finished copying {} files", files.len());
...@@ -285,7 +344,7 @@ fn main() { ...@@ -285,7 +344,7 @@ fn main() {
process::exit(0); process::exit(0);
}, },
Err(err) => { Err(err) => {
eprintln!("installer_tui: failed to install: {:?}", err); eprintln!("installer_tui: failed to install: {}", err);
process::exit(1); process::exit(1);
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment