<commit_before>use std::cmp::Ordering;
use utils::{slice_str, calculate_ratio};

#[derive(Debug, Clone, Copy)]
pub struct Match{
	first_start: usize,
	second_start: usize,
	size: usize
}

impl Ord for Match {
    fn cmp(&self, other: &Match) -> Ordering {
        self.size.cmp(&other.size)
    }
}

impl PartialOrd for Match {
    fn partial_cmp(&self, other: &Match) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for Match {
    fn eq(&self, other: &Match) -> bool {
        self.size == other.size
    }
}

impl Eq for Match { }

impl Match{
	fn new(first_start: usize, second_start: usize, size: usize) -> Match {
		Match{
			first_start: first_start,
			second_start: second_start,
			size: size
		}
	}
}

#[derive(Debug, Clone)]
pub struct Opcode{
	pub tag: String,
	pub first_start: usize,
	pub first_end: usize,
	pub second_start: usize,
	pub second_end: usize
}

impl Opcode{
	fn new(tag: String, first_start: usize, first_end: usize, second_start: usize, second_end: usize) -> Opcode {
		Opcode{
			tag: tag,
			first_start: first_start,
			first_end: first_end,
			second_start: second_start,
			second_end: second_end
		}
	}
}

pub struct SequenceMatcher<'a>{
	first_sequence: &'a str,
	second_sequence: &'a str,
	matching_blocks: Option<Vec<Match>>,
	opcodes: Option<Vec<Opcode>>,
	autojunk: bool
}

impl<'a> SequenceMatcher<'a>{
	pub fn new(first_sequence: &'a str, second_sequence: &'a str) -> SequenceMatcher<'a> {
		SequenceMatcher{
			first_sequence: first_sequence,
			second_sequence: second_sequence,
			matching_blocks: None,
			opcodes: None,
			autojunk: true,

		}
	}

	pub fn set_seqs(&mut self, first_sequence: &'a str, second_sequence: &'a str) {
		self.set_first_seq(first_sequence);
		self.set_second_seq(second_sequence);
	}

	pub fn set_first_seq(&mut self, sequence: &'a str) {
		self.first_sequence = sequence;
		self.matching_blocks = None;
		self.opcodes = None;
	}

	pub fn set_second_seq(&mut self, sequence: &'a str) {
		self.second_sequence = sequence;
		self.matching_blocks = None;
		self.opcodes = None;
		//self.fullbcount = None
        //self.__chain_b()
	}

	pub fn find_longest_match(&self, first_start: usize, first_end: usize, second_start: usize, second_end: usize) -> Option<Match> {
		let first_sequence: Vec<char> = slice_str(self.first_sequence, first_start, first_end).unwrap_or("").chars().collect();
		let second_sequence: Vec<char> = slice_str(self.second_sequence, second_start, second_end).unwrap_or("").chars().collect();
		let mut max_i = 0;
		let mut max_j = 0;
		let mut arr: Vec<Vec<usize>> = vec![vec![0; second_sequence.len() + 1]; first_sequence.len() + 1];
		for i in 0..first_sequence.len(){
			for j in 0..second_sequence.len(){
				if first_sequence[i] == second_sequence[j]{
					arr[i + 1][j + 1] = arr[i][j] + 1;
					if arr[i + 1][j + 1] > arr[max_i][max_j] {
                        max_i = i + 1;
                        max_j = j + 1;
                   }
				}
			}
		}
		if max_i == 0 && max_j == 0{
			return None
		}
		else{
			let size = arr[max_i][max_j];
			Some(Match{
				first_start: max_i - size + first_start,
				second_start: max_j - size + second_start,
				size: size
			})
		}
	}

	pub fn get_matching_blocks(&mut self) -> Vec<Match> {
		if self.matching_blocks.as_ref().is_some(){
            return self.matching_blocks.as_ref().unwrap().clone()
		}
		let (first_length, second_length) = (self.first_sequence.len(), self.second_sequence.len());
		let mut matches = Vec::new();
		let mut queue = vec![(0, first_length, 0, second_length)];
		while !queue.is_empty(){
			let (first_start, first_end, second_start, second_end) = queue.pop().unwrap();
			let m = self.find_longest_match(first_start, first_end, second_start, second_end);
			match m {
			    Some(m) => {
			    	if first_start < m.first_start && second_start < m.second_start{
			    		queue.push((first_start, m.first_start, second_start, m.second_start));
			    	}
			    	if m.first_start + m.size < first_end && m.second_start + m.size < second_end{
			    		queue.push((m.first_start + m.size, first_end, m.second_start + m.size, second_end));
			    	}
			    	matches.push(m);
			    },
			    None => {},
			}
		}
		matches.sort_by(|a, b| b.cmp(a));
		let (mut first_start, mut second_start, mut size) = (0, 0, 0);
		let mut non_adjacent = Vec::new();
		for m in &matches{
			if first_start + size == m.first_start && second_start + size == m.second_start{
				size += m.size
			}
			else {
			    if size != 0{
			    	non_adjacent.push(Match::new(first_start, second_start, size));
			    }
			    first_start = m.first_start;
			    second_start = m.second_start;
			    size = m.size;
			}
		}
		if size != 0{
			non_adjacent.push(Match::new(first_start, second_start, size));
		}
		non_adjacent.push(Match::new(first_length, second_length, 0));
		self.matching_blocks = Some(non_adjacent);
		self.matching_blocks.as_ref().unwrap().clone()
	}

	pub fn get_opcodes(&mut self) -> Vec<Opcode>{
		if self.opcodes.as_ref().is_some(){
            return self.opcodes.as_ref().unwrap().clone()
		}
		let mut opcodes = Vec::new();
		let (mut i, mut j) = (0, 0);
		for m in self.get_matching_blocks(){
			let mut tag = String::new();
			if i < m.first_start && j < m.second_start{
				tag = String::from("replace");
			}
			else if i < m.first_start{
				tag = String::from("delete");
			}
			else if j < m.second_start{
				tag = String::from("insert");
			}
			if !tag.is_empty(){
				opcodes.push( Opcode::new(tag, i, m.first_start, j, m.second_start) );
			}
			i = m.first_start + m.size;
			j = m.second_start + m.size;
			if m.size != 0{
				opcodes.push( Opcode::new(String::from("equal"), m.first_start, i, m.second_start, j) );
			}
		}
		self.opcodes = Some(opcodes);
		return self.opcodes.as_ref().unwrap().clone()
	}

	pub fn ratio(&mut self) -> f32{
		let matches = self.get_matching_blocks().iter().fold(0, |res, &m| res + m.size);
		calculate_ratio(matches, self.first_sequence.len() + self.second_sequence.len())
	}
}
<commit_msg>Add function to get grouping opcodes for sequence matcher struct<commit_after>use std::cmp::{Ordering, max, min};
use utils::{slice_str, calculate_ratio};

#[derive(Debug, Clone, Copy)]
pub struct Match{
	first_start: usize,
	second_start: usize,
	size: usize
}

impl Ord for Match {
    fn cmp(&self, other: &Match) -> Ordering {
        self.size.cmp(&other.size)
    }
}

impl PartialOrd for Match {
    fn partial_cmp(&self, other: &Match) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialEq for Match {
    fn eq(&self, other: &Match) -> bool {
        self.size == other.size
    }
}

impl Eq for Match { }

impl Match{
	fn new(first_start: usize, second_start: usize, size: usize) -> Match {
		Match{
			first_start: first_start,
			second_start: second_start,
			size: size
		}
	}
}

#[derive(Debug, Clone)]
pub struct Opcode{
	pub tag: String,
	pub first_start: usize,
	pub first_end: usize,
	pub second_start: usize,
	pub second_end: usize
}

impl Opcode{
	fn new(tag: String, first_start: usize, first_end: usize, second_start: usize, second_end: usize) -> Opcode {
		Opcode{
			tag: tag,
			first_start: first_start,
			first_end: first_end,
			second_start: second_start,
			second_end: second_end
		}
	}
}

pub struct SequenceMatcher<'a>{
	first_sequence: &'a str,
	second_sequence: &'a str,
	matching_blocks: Option<Vec<Match>>,
	opcodes: Option<Vec<Opcode>>,
	autojunk: bool
}

impl<'a> SequenceMatcher<'a>{
	pub fn new(first_sequence: &'a str, second_sequence: &'a str) -> SequenceMatcher<'a> {
		SequenceMatcher{
			first_sequence: first_sequence,
			second_sequence: second_sequence,
			matching_blocks: None,
			opcodes: None,
			autojunk: true,

		}
	}

	pub fn set_seqs(&mut self, first_sequence: &'a str, second_sequence: &'a str) {
		self.set_first_seq(first_sequence);
		self.set_second_seq(second_sequence);
	}

	pub fn set_first_seq(&mut self, sequence: &'a str) {
		self.first_sequence = sequence;
		self.matching_blocks = None;
		self.opcodes = None;
	}

	pub fn set_second_seq(&mut self, sequence: &'a str) {
		self.second_sequence = sequence;
		self.matching_blocks = None;
		self.opcodes = None;
		//self.fullbcount = None
        //self.__chain_b()
	}

	pub fn find_longest_match(&self, first_start: usize, first_end: usize, second_start: usize, second_end: usize) -> Option<Match> {
		let first_sequence: Vec<char> = slice_str(self.first_sequence, first_start, first_end).unwrap_or("").chars().collect();
		let second_sequence: Vec<char> = slice_str(self.second_sequence, second_start, second_end).unwrap_or("").chars().collect();
		let mut max_i = 0;
		let mut max_j = 0;
		let mut arr: Vec<Vec<usize>> = vec![vec![0; second_sequence.len() + 1]; first_sequence.len() + 1];
		for i in 0..first_sequence.len(){
			for j in 0..second_sequence.len(){
				if first_sequence[i] == second_sequence[j]{
					arr[i + 1][j + 1] = arr[i][j] + 1;
					if arr[i + 1][j + 1] > arr[max_i][max_j] {
                        max_i = i + 1;
                        max_j = j + 1;
                   }
				}
			}
		}
		if max_i == 0 && max_j == 0{
			return None
		}
		else{
			let size = arr[max_i][max_j];
			Some(Match{
				first_start: max_i - size + first_start,
				second_start: max_j - size + second_start,
				size: size
			})
		}
	}

	pub fn get_matching_blocks(&mut self) -> Vec<Match> {
		if self.matching_blocks.as_ref().is_some(){
            return self.matching_blocks.as_ref().unwrap().clone()
		}
		let (first_length, second_length) = (self.first_sequence.len(), self.second_sequence.len());
		let mut matches = Vec::new();
		let mut queue = vec![(0, first_length, 0, second_length)];
		while !queue.is_empty(){
			let (first_start, first_end, second_start, second_end) = queue.pop().unwrap();
			let m = self.find_longest_match(first_start, first_end, second_start, second_end);
			match m {
			    Some(m) => {
			    	if first_start < m.first_start && second_start < m.second_start{
			    		queue.push((first_start, m.first_start, second_start, m.second_start));
			    	}
			    	if m.first_start + m.size < first_end && m.second_start + m.size < second_end{
			    		queue.push((m.first_start + m.size, first_end, m.second_start + m.size, second_end));
			    	}
			    	matches.push(m);
			    },
			    None => {},
			}
		}
		matches.sort_by(|a, b| b.cmp(a));
		let (mut first_start, mut second_start, mut size) = (0, 0, 0);
		let mut non_adjacent = Vec::new();
		for m in &matches{
			if first_start + size == m.first_start && second_start + size == m.second_start{
				size += m.size
			}
			else {
			    if size != 0{
			    	non_adjacent.push(Match::new(first_start, second_start, size));
			    }
			    first_start = m.first_start;
			    second_start = m.second_start;
			    size = m.size;
			}
		}
		if size != 0{
			non_adjacent.push(Match::new(first_start, second_start, size));
		}
		non_adjacent.push(Match::new(first_length, second_length, 0));
		self.matching_blocks = Some(non_adjacent);
		self.matching_blocks.as_ref().unwrap().clone()
	}

	pub fn get_opcodes(&mut self) -> Vec<Opcode>{
		if self.opcodes.as_ref().is_some(){
            return self.opcodes.as_ref().unwrap().clone()
		}
		let mut opcodes = Vec::new();
		let (mut i, mut j) = (0, 0);
		for m in self.get_matching_blocks(){
			let mut tag = String::new();
			if i < m.first_start && j < m.second_start{
				tag = String::from("replace");
			}
			else if i < m.first_start{
				tag = String::from("delete");
			}
			else if j < m.second_start{
				tag = String::from("insert");
			}
			if !tag.is_empty(){
				opcodes.push( Opcode::new(tag, i, m.first_start, j, m.second_start) );
			}
			i = m.first_start + m.size;
			j = m.second_start + m.size;
			if m.size != 0{
				opcodes.push( Opcode::new(String::from("equal"), m.first_start, i, m.second_start, j) );
			}
		}
		self.opcodes = Some(opcodes);
		return self.opcodes.as_ref().unwrap().clone()
	}

	/*
	codes = self.get_opcodes()
        if not codes:
            codes = [("equal", 0, 1, 0, 1)]
        # Fixup leading and trailing groups if they show no changes.
        if codes[0][0] == 'equal':
            tag, i1, i2, j1, j2 = codes[0]
            codes[0] = tag, max(i1, i2-n), i2, max(j1, j2-n), j2
        if codes[-1][0] == 'equal':
            tag, i1, i2, j1, j2 = codes[-1]
            codes[-1] = tag, i1, min(i2, i1+n), j1, min(j2, j1+n)

        nn = n + n
        group = []
        for tag, i1, i2, j1, j2 in codes:
            # End the current group and start a new one whenever
            # there is a large range with no changes.
            if tag == 'equal' and i2-i1 > nn:
                group.append((tag, i1, min(i2, i1+n), j1, min(j2, j1+n)))
                yield group
                group = []
                i1, j1 = max(i1, i2-n), max(j1, j2-n)
            group.append((tag, i1, i2, j1 ,j2))
        if group and not (len(group)==1 and group[0][0] == 'equal'):
            yield group
           */
	pub fn get_grouped_opcodes(&mut self, n: usize) -> Vec<Vec<Opcode>> {
		let mut res = Vec::new();
		let mut codes = self.get_opcodes();
		if codes.is_empty() {
			codes.push(Opcode::new("equal".to_string(), 0, 1, 0, 1));
		}
		if codes.first().unwrap().tag == "equal" {
			let mut opcode = codes.first_mut().unwrap();
			opcode.first_start = max(opcode.first_start, opcode.first_end - n);
			opcode.second_start = max(opcode.second_start, opcode.second_end - n);
		}
		if codes.last().unwrap().tag == "equal" {
			let mut opcode = codes.last_mut().unwrap();
			opcode.first_end = min(opcode.first_start + n, opcode.first_end);
			opcode.second_end = min(opcode.second_start + n, opcode.second_end);
		}
		let nn = n + n;
		let mut group = Vec::new();
		for code in &codes {
			let (mut first_start, mut second_start) = (code.first_start, code.second_start);
			if code.tag == "equal" && code.first_end-code.first_start > nn {
				group.push( Opcode::new(code.tag.clone(), code.first_start, min(code.first_end, code.first_start+n),
					code.second_start, min(code.second_end, code.second_start+n)) );
				res.push(group.clone());
				group.clear();
				first_start = max(first_start, code.first_end-n);
				second_start = max(second_start, code.second_end - n);
			}
			group.push( Opcode::new(code.tag.clone(), first_start, code.first_end, second_start, code.second_end) );
		}
		if !group.is_empty() && !(group.len()==1 && group.first().unwrap().tag == "equal") {
			res.push(group.clone());
		}
		res
	}

	pub fn ratio(&mut self) -> f32{
		let matches = self.get_matching_blocks().iter().fold(0, |res, &m| res + m.size);
		calculate_ratio(matches, self.first_sequence.len() + self.second_sequence.len())
	}
}
<|endoftext|>


<commit_before>export Font, test_font_bin, create_test_font;

use glyph::GlyphIndex;
use vec_to_ptr = vec::unsafe::to_ptr;
use libc::{ c_int, c_double, c_ulong };
use ptr::{ null, addr_of };
use native_font::NativeFont;
use font_library::FontLibrary;

#[doc = "
A font handle. Layout can use this to calculate glyph metrics
and the renderer can use it to render text.
"]
struct Font {
    fontbuf: @~[u8],
    native_font: NativeFont,
}

impl Font {
    fn buf() -> @~[u8] {
        self.fontbuf
    }

    fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
        self.native_font.glyph_index(codepoint)
    }

    fn glyph_h_advance(glyph: GlyphIndex) -> int {
        match self.native_font.glyph_h_advance(glyph) {
          Some(adv) => adv,
          None => /* FIXME: Need fallback strategy */ 10
        }
    }
}

fn Font(fontbuf: ~[u8], native_font: NativeFont) -> Font {
    Font {
        fontbuf : @fontbuf,
        native_font : native_font,
    }
}

const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf");

fn test_font_bin() -> ~[u8] {
    return vec::from_fn(33004, |i| TEST_FONT[i]);
}

fn should_destruct_on_fail_without_leaking() {
    #[test];
    #[should_fail];

    let lib = FontLibrary();
    let _font = lib.get_test_font();
    fail;
}

fn should_get_glyph_indexes() {
    #[test];

    let lib = FontLibrary();
    let font = lib.get_test_font();
    let glyph_idx = font.glyph_index('w');
    assert glyph_idx == Some(40u);
}

fn should_get_glyph_advance() {
    #[test];

    let lib = FontLibrary();
    let font = lib.get_test_font();
    let x = font.glyph_h_advance(40u);
    assert x == 15;
}

fn should_be_able_to_create_instances_in_multiple_threads() {
    #[test];

    for iter::repeat(10u) {
        do task::spawn {
            let lib = FontLibrary();
            let _font = lib.get_test_font();
        }
    }
}

<commit_msg>Fix font segfaults<commit_after>export Font, test_font_bin, create_test_font;

use glyph::GlyphIndex;
use vec_to_ptr = vec::unsafe::to_ptr;
use libc::{ c_int, c_double, c_ulong };
use ptr::{ null, addr_of };
use native_font::NativeFont;
use font_library::FontLibrary;

#[doc = "
A font handle. Layout can use this to calculate glyph metrics
and the renderer can use it to render text.
"]
struct Font {
    fontbuf: @~[u8],
    native_font: NativeFont,
}

impl Font {
    fn buf() -> @~[u8] {
        self.fontbuf
    }

    fn glyph_index(codepoint: char) -> Option<GlyphIndex> {
        self.native_font.glyph_index(codepoint)
    }

    fn glyph_h_advance(glyph: GlyphIndex) -> int {
        match self.native_font.glyph_h_advance(glyph) {
          Some(adv) => adv,
          None => /* FIXME: Need fallback strategy */ 10
        }
    }
}

fn Font(fontbuf: ~[u8], +native_font: NativeFont) -> Font {
    Font {
        fontbuf : @fontbuf,
        native_font : native_font,
    }
}

const TEST_FONT: [u8 * 33004] = #include_bin("JosefinSans-SemiBold.ttf");

fn test_font_bin() -> ~[u8] {
    return vec::from_fn(33004, |i| TEST_FONT[i]);
}

fn should_destruct_on_fail_without_leaking() {
    #[test];
    #[should_fail];

    let lib = FontLibrary();
    let _font = lib.get_test_font();
    fail;
}

fn should_get_glyph_indexes() {
    #[test];

    let lib = FontLibrary();
    let font = lib.get_test_font();
    let glyph_idx = font.glyph_index('w');
    assert glyph_idx == Some(40u);
}

fn should_get_glyph_advance() {
    #[test];

    let lib = FontLibrary();
    let font = lib.get_test_font();
    let x = font.glyph_h_advance(40u);
    assert x == 15;
}

fn should_be_able_to_create_instances_in_multiple_threads() {
    #[test];

    for iter::repeat(10u) {
        do task::spawn {
            let lib = FontLibrary();
            let _font = lib.get_test_font();
        }
    }
}

<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::runtime::bootstrap;
use libra_config::utils;
use libra_mempool::mocks::MockSharedMempool;
use libra_proptest_helpers::ValueGenerator;
use libra_temppath::TempPath;
use libra_types::transaction::SignedTransaction;
use libradb::LibraDB;
use reqwest::blocking::Client;
use std::sync::Arc;

#[test]
fn test_json_rpc_service_fuzzer() {
    let mut gen = ValueGenerator::new();
    let data = generate_corpus(&mut gen);
    fuzzer(&data);
}

/// generate_corpus produces an arbitrary transaction to submit to JSON RPC service
pub fn generate_corpus(gen: &mut ValueGenerator) -> Vec<u8> {
    // use proptest to generate a SignedTransaction
    let txn = gen.generate(proptest::arbitrary::any::<SignedTransaction>());
    let payload = hex::encode(lcs::to_bytes(&txn).unwrap());
    let request =
        serde_json::json!({"jsonrpc": "2.0", "method": "submit", "params": [payload], "id": 1});
    serde_json::to_vec(&request).expect("failed to convert JSON to byte array")
}

pub fn fuzzer(data: &[u8]) {
    // set up mock Shared Mempool
    let smp = MockSharedMempool::new(None);

    // set up JSON RPC service
    let tmp_dir = TempPath::new();
    let db = LibraDB::new(&tmp_dir);
    let port = utils::get_available_port();
    let address = format!("0.0.0.0:{}", port);
    let _runtime = bootstrap(address.parse().unwrap(), Arc::new(db), smp.ac_client);

    let client = Client::new();
    let url = format!("http://{}", address);
    let request: serde_json::Value =
        serde_json::from_slice(data).expect("failed to convert byte array to JSON");
    let response = client
        .post(&url) // address
        .json(&request)
        .send()
        .expect("failed to send request to JSON RPC server");

    let response: serde_json::Value = response.json().expect("failed to convert response to JSON");

    let json_rpc_protocol = response.get("jsonrpc");
    assert_eq!(
        json_rpc_protocol,
        Some(&serde_json::Value::String("2.0".to_string())),
        "JSON RPC response with incorrect protocol: {:?}",
        json_rpc_protocol
    );
    assert!(
        response.get("error").is_none(),
        "expected no error in JSON RPC response",
    );

    if let Some(result) = response.get("result") {
        let response_id: u64 = serde_json::from_value(response.get("id").unwrap().clone())
            .expect("failed to get ID from response");
        assert_eq!(response_id, 1, "mismatch ID in JSON RPC");
        assert!(
            *result == serde_json::Value::Null,
            "Received unexpected result payload from txn submission: {:?}",
            result
        );
    } else {
        panic!("Received JSON RPC response with no result payload");
    }
}
<commit_msg>[JSON RPC] make fuzzer not panic on parsing invalid inputs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::runtime::bootstrap;
use libra_config::utils;
use libra_mempool::mocks::MockSharedMempool;
use libra_proptest_helpers::ValueGenerator;
use libra_temppath::TempPath;
use libra_types::transaction::SignedTransaction;
use libradb::LibraDB;
use reqwest::blocking::Client;
use std::sync::Arc;

#[test]
fn test_json_rpc_service_fuzzer() {
    let mut gen = ValueGenerator::new();
    let data = generate_corpus(&mut gen);
    fuzzer(&data);
}

/// generate_corpus produces an arbitrary transaction to submit to JSON RPC service
pub fn generate_corpus(gen: &mut ValueGenerator) -> Vec<u8> {
    // use proptest to generate a SignedTransaction
    let txn = gen.generate(proptest::arbitrary::any::<SignedTransaction>());
    let payload = hex::encode(lcs::to_bytes(&txn).unwrap());
    let request =
        serde_json::json!({"jsonrpc": "2.0", "method": "submit", "params": [payload], "id": 1});
    serde_json::to_vec(&request).expect("failed to convert JSON to byte array")
}

pub fn fuzzer(data: &[u8]) {
    // set up mock Shared Mempool
    let smp = MockSharedMempool::new(None);

    // set up JSON RPC service
    let tmp_dir = TempPath::new();
    let db = LibraDB::new(&tmp_dir);
    let port = utils::get_available_port();
    let address = format!("0.0.0.0:{}", port);
    let _runtime = bootstrap(address.parse().unwrap(), Arc::new(db), smp.ac_client);

    let client = Client::new();
    let url = format!("http://{}", address);
    let json_request;
    match serde_json::from_slice::<serde_json::Value>(data) {
        Err(_) => return, // should not throw error or panic on invalid fuzzer inputs
        Ok(request) => json_request = request,
    };

    let response = client
        .post(&url) // address
        .json(&json_request)
        .send()
        .expect("failed to send request to JSON RPC server");

    let response: serde_json::Value = response.json().expect("failed to convert response to JSON");

    let json_rpc_protocol = response.get("jsonrpc");
    assert_eq!(
        json_rpc_protocol,
        Some(&serde_json::Value::String("2.0".to_string())),
        "JSON RPC response with incorrect protocol: {:?}",
        json_rpc_protocol
    );
    assert!(
        response.get("error").is_none(),
        "expected no error in JSON RPC response",
    );

    if let Some(result) = response.get("result") {
        let response_id: u64 = serde_json::from_value(response.get("id").unwrap().clone())
            .expect("failed to get ID from response");
        assert_eq!(response_id, 1, "mismatch ID in JSON RPC");
        assert!(
            *result == serde_json::Value::Null,
            "Received unexpected result payload from txn submission: {:?}",
            result
        );
    } else {
        panic!("Received JSON RPC response with no result payload");
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::build(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
        let list = glob(&self.prefix_of_files_for_module(m)[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = p.write(f.contents())
            .or_else(|err| {
                let mut serr = StorageBackendError::build(
                    "Parser::write()",
                    "Cannot parse file contents",
                    "Cannot translate internal representation of file contents into on-disk representation",
                    None
                );
                serr.caused_by = Some(&err);
                Err(serr)
            });

        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            "", None
                        );
                    err.caused_by = Some(&ioerr);
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                "", None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.storepath.clone() + owner.name() + "-" + &id[..] + ".imag"
    }

}

#[derive(Debug)]
pub struct StorageBackendError<'a> {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl<'a> StorageBackendError<'a> {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError<'a>
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
           data  : Option<String>) -> StorageBackendError<'a>
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl<'a> Error for StorageBackendError<'a> {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError<'a> {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<commit_msg>Outsource file to string parsing<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::build(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
        let list = glob(&self.prefix_of_files_for_module(m)[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            "", None
                        );
                    err.caused_by = Some(&ioerr);
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                "", None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.storepath.clone() + owner.name() + "-" + &id[..] + ".imag"
    }

}

#[derive(Debug)]
pub struct StorageBackendError<'a> {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl<'a> StorageBackendError<'a> {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError<'a>
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
           data  : Option<String>) -> StorageBackendError<'a>
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl<'a> Error for StorageBackendError<'a> {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError<'a> {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError<'a>> {
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot parse file contents",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(&err);
            Err(serr)
        })
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;

use super::file::FileID;
use super::file::File;
use module::Module;

type BackendOperationResult = Result<(), StorageBackendError>;

pub struct StorageBackend<'a> {
    basepath: String,
    module: &'a Module,
}

impl<'a> StorageBackend<'a> {

    fn new() -> StorageBackend<'a> {
    }

    fn getFileList() -> Vec<(String, FileID)> {
    }

    fn createEmpty() -> FileID {
    }

    fn createFile() -> File {
    }

    fn writeFile(f: File) -> BackendOperationResult {
    }

    fn createFileWithContent(content: String) -> BackendOperationResult {
    }

    fn readFile(id: FileID) -> String {
    }

    // TODO: Meta files are not covered yet

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub explanation: String,        // A long, user friendly description
    pub dataDump: Option<String>    // Data dump, if any
}

impl StorageBackendError {
    fn new(action: &'static str,
           desc  : &'static str,
           explan: &'static str,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            explanation:    String::from(explan),
            dataDump:       data,
        }
    }
}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}\n\n{}",
               self.action, self.desc, self.explanation)
    }
}

<commit_msg>Implement StorageBackend::new()<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;

use super::file::FileID;
use super::file::File;
use module::Module;

type BackendOperationResult = Result<(), StorageBackendError>;

pub struct StorageBackend<'a> {
    basepath: String,
    module: &'a Module,
}

impl<'a> StorageBackend<'a> {

    fn new(bashpath: String, module: &'a Module) -> StorageBackend<'a> {
        StorageBackend {
            basepath: basepath,
            module: module,
        }
    }

    fn getFileList() -> Vec<(String, FileID)> {
    }

    fn createEmpty() -> FileID {
    }

    fn createFile() -> File {
    }

    fn writeFile(f: File) -> BackendOperationResult {
    }

    fn createFileWithContent(content: String) -> BackendOperationResult {
    }

    fn readFile(id: FileID) -> String {
    }

    // TODO: Meta files are not covered yet

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub explanation: String,        // A long, user friendly description
    pub dataDump: Option<String>    // Data dump, if any
}

impl StorageBackendError {
    fn new(action: &'static str,
           desc  : &'static str,
           explan: &'static str,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            explanation:    String::from(explan),
            dataDump:       data,
        }
    }
}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}\n\n{}",
               self.action, self.desc, self.explanation)
    }
}

<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::io::Read;
use std::io::Write;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult = Result<(), StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
}

impl StorageBackend {

    pub fn new(basepath: String) -> StorageBackend {
        StorageBackend {
            basepath: basepath,
        }
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self) -> Option<Vec<FileID>> {
        debug!("Getting files from {}", self.basepath);
        let list = glob(&self.basepath[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<'a, HP>(&self, f: File, p: &Parser<HP>) ->
        Result<BackendOperationResult, ParserError>
        where HP: FileHeaderParser<'a>
    {
        let written = p.write(f.contents());
        if let Ok(string) = written {
            let path = self.build_filepath(&f);
            debug!("Writing file: {}", path);
            debug!("    contents: {}", string);
            Ok(Ok(()))
        } else {
            debug!("Error parsing : {:?}", f.contents());
            Err(written.err().unwrap())
        }
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<'a, HP>(&self, f: File, p: &Parser<HP>)
        -> Result<BackendOperationResult, ParserError>
        where HP: FileHeaderParser<'a>
    {
        let contents = p.write(f.contents());

        if contents.is_err() {
            debug!("Error parsing contents: {:?}", f.contents());
            return Err(contents.err().unwrap());
        }

        let content = contents.unwrap();
        debug!("Success parsing content : {}", content);

        let path = self.build_filepath(&f);
        debug!("Trying to write to file at {}", path);
        if let Err(_) = FSFile::open(&path) {
            debug!("Error opening {}", path);
            return Ok(Err(StorageBackendError::new(
                String::from("File::open()"),
                format!("Tried to open '{}'", path),
                String::from("Tried to update contents of this file, though file doesn't exist"),
                None)))
        }

        if let Ok(mut file) = FSFile::create(&path) {
            if let Err(writeerr) = file.write_all(&content.clone().into_bytes()) {
                debug!("Error writing to {}", path);
                return Ok(Err(StorageBackendError::new(
                    String::from("File::write()"),
                    format!("Tried to write '{}'", path),
                    String::from("Tried to write contents of this file, though operation did not succeed"),
                    Some(content))))
            }
        }

        debug!("Successfully written to file.");
        Ok(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, id: FileID, p: &Parser<HP>) -> Option<File>
        where HP: FileHeaderParser<'a>
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(id, h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.id())
    }

    fn build_filepath_with_id(&self, id: FileID) -> String {
        debug!("Building filepath for id '{}'", id);
        self.basepath.clone() + &id[..]
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>   // Data dump, if any
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
        }
    }
}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

<commit_msg>Add StorageBackendError::caused_by member<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::io::Read;
use std::io::Write;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult = Result<(), StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
}

impl StorageBackend {

    pub fn new(basepath: String) -> StorageBackend {
        StorageBackend {
            basepath: basepath,
        }
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self) -> Option<Vec<FileID>> {
        debug!("Getting files from {}", self.basepath);
        let list = glob(&self.basepath[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<'a, HP>(&self, f: File, p: &Parser<HP>) ->
        Result<BackendOperationResult, ParserError>
        where HP: FileHeaderParser<'a>
    {
        let written = p.write(f.contents());
        if let Ok(string) = written {
            let path = self.build_filepath(&f);
            debug!("Writing file: {}", path);
            debug!("    contents: {}", string);
            Ok(Ok(()))
        } else {
            debug!("Error parsing : {:?}", f.contents());
            Err(written.err().unwrap())
        }
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<'a, HP>(&self, f: File, p: &Parser<HP>)
        -> Result<BackendOperationResult, ParserError>
        where HP: FileHeaderParser<'a>
    {
        let contents = p.write(f.contents());

        if contents.is_err() {
            debug!("Error parsing contents: {:?}", f.contents());
            return Err(contents.err().unwrap());
        }

        let content = contents.unwrap();
        debug!("Success parsing content : {}", content);

        let path = self.build_filepath(&f);
        debug!("Trying to write to file at {}", path);
        if let Err(_) = FSFile::open(&path) {
            debug!("Error opening {}", path);
            return Ok(Err(StorageBackendError::new(
                String::from("File::open()"),
                format!("Tried to open '{}'", path),
                String::from("Tried to update contents of this file, though file doesn't exist"),
                None)))
        }

        if let Ok(mut file) = FSFile::create(&path) {
            if let Err(writeerr) = file.write_all(&content.clone().into_bytes()) {
                debug!("Error writing to {}", path);
                return Ok(Err(StorageBackendError::new(
                    String::from("File::write()"),
                    format!("Tried to write '{}'", path),
                    String::from("Tried to write contents of this file, though operation did not succeed"),
                    Some(content))))
            }
        }

        debug!("Successfully written to file.");
        Ok(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, id: FileID, p: &Parser<HP>) -> Option<File>
        where HP: FileHeaderParser<'a>
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(id, h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.id())
    }

    fn build_filepath_with_id(&self, id: FileID) -> String {
        debug!("Building filepath for id '{}'", id);
        self.basepath.clone() + &id[..]
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }
}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::logging::*;
use crate::scheduler::*;

#[allow(unused_assignments)]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn sys_invalid() {
	let mut rax: i64 = 0;

	llvm_asm!("push %rax; pop $0" : "=r"(rax));

	error!("Invalid syscall {}", rax);
	do_exit();
}
<commit_msg>removing llvm_asm to avoid compiler warnings<commit_after>// Copyright (c) 2017 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::logging::*;
use crate::scheduler::*;

#[no_mangle]
extern "C" fn invalid_syscall(sys_no: u64) {
	error!("Invalid syscall {}", sys_no);
	do_exit();
}

#[allow(unused_assignments)]
#[no_mangle]
#[naked]
pub unsafe extern "C" fn sys_invalid() {
	asm!("mov rdi, rax",
		"call {}",
		sym invalid_syscall,
		options(noreturn)
	);
}
<|endoftext|>


<commit_before>extern crate termion;

pub fn main_loop() {

    loop {

    }

}
<commit_msg>play with termion examples<commit_after>extern crate termion;

use self::termion::event::Key;
use self::termion::input::TermRead;
use self::termion::raw::IntoRawMode;

use std::io::{Write, stdout, stdin};

pub fn main_loop() {

    let mut stdout = stdout().into_raw_mode().unwrap();

    write!(stdout,
           "{}{}",
           termion::cursor::Goto(1, 1),
           termion::clear::All)
        .unwrap();
    stdout.flush().unwrap();

    let mut quit = false;
    while !quit {
        let stdin = stdin();
        for c in stdin.keys() {

            write!(stdout,
                   "{}{}",
                   termion::cursor::Goto(1, 1),
                   termion::clear::All)
                .unwrap();

            // Print the key we type...
            match c.unwrap() {
                // Exit.
                Key::Char('q') => {
                    quit = true;
                    break;
                }
                Key::Char(c) => println!("{}", c),
                Key::Alt(c) => println!("Alt-{}", c),
                Key::Ctrl(c) => println!("Ctrl-{}", c),
                Key::Left => println!("<left>"),
                Key::Right => println!("<right>"),
                Key::Up => println!("<up>"),
                Key::Down => println!("<down>"),
                _ => println!("Other"),
            }

            // Flush again.
            stdout.flush().unwrap();
        }
    }
}
<|endoftext|>


<commit_before>#[allow(unused_imports)]
#[macro_use]
extern crate log;
extern crate libc;
extern crate env_logger;
extern crate catfs;
extern crate rand;
extern crate fuse;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Write};
use std::process::Command;
use std::path::{Path, PathBuf};
use std::os::unix::fs::FileExt;

use rand::{thread_rng, Rng};

use catfs::CatFS;
use catfs::catfs::error;

#[macro_use]
mod test_suite;

trait Fixture {
    fn setup() -> error::Result<Self>
    where
        Self: std::marker::Sized;
    fn teardown(self) -> error::Result<()>;
}

struct CatFSTests<'a> {
    prefix: PathBuf,
    mnt: PathBuf,
    src: *const PathBuf,
    cache: *const PathBuf,
    session: Option<fuse::BackgroundSession<'a>>,
}

fn copy_all(dir1: &AsRef<Path>, dir2: &AsRef<Path>) -> error::Result<()> {
    fs::create_dir(dir2)?;

    for entry in fs::read_dir(dir1)? {
        let entry = entry?;
        let to = dir2.as_ref().join(entry.file_name());

        if entry.file_type()?.is_dir() {
            copy_all(&entry.path(), &to)?;
        } else {
            fs::copy(entry.path(), to)?;
        }
    }

    return Ok(());
}

impl<'a> CatFSTests<'a> {
    fn get_orig_dir() -> PathBuf {
        let manifest = env::var_os("CARGO_MANIFEST_DIR").unwrap();
        return PathBuf::from(manifest).join("tests/resources");
    }

    fn get_from(&self) -> PathBuf {
        return self.prefix.join("resources");
    }

    fn extend(&self, s: *const PathBuf) -> &'static PathBuf {
        return unsafe { std::mem::transmute(s) };
    }

    fn mount(&self) -> error::Result<fuse::BackgroundSession<'a>> {
        let src = self.extend(self.src);
        let cache = self.extend(self.cache);
        let fs = CatFS::new(src, cache)?;

        return Ok(unsafe { fuse::spawn_mount(fs, &self.mnt, &[])? });
    }
}

impl<'a> Fixture for CatFSTests<'a> {
    fn setup() -> error::Result<CatFSTests<'a>> {
        #[allow(unused_must_use)] env_logger::init();

        let manifest = env::var_os("CARGO_MANIFEST_DIR").unwrap();
        let prefix = PathBuf::from(manifest).join("target/test").join(
            thread_rng().gen_ascii_chars().take(10).collect::<String>(),
        );
        let mnt = prefix.join("mnt");
        let resources = prefix.join("resources");
        let cache = prefix.join("cache");

        fs::create_dir_all(&mnt)?;
        fs::create_dir_all(&cache)?;

        copy_all(&CatFSTests::get_orig_dir(), &resources)?;

        let mut t = CatFSTests {
            prefix: prefix,
            mnt: mnt,
            src: &resources as *const PathBuf,
            cache: &cache as *const PathBuf,
            session: Default::default(),
        };

        std::mem::forget(resources);
        std::mem::forget(cache);

        t.session = Some(t.mount()?);

        return Ok(t);
    }

    fn teardown(self) -> error::Result<()> {
        {
            // move out the session to let us umount first
            #[allow(unused_variables)]
            let session = self.session;
        }
        fs::remove_dir_all(&self.prefix)?;
        // TODO do I need to free self.src/cache?
        return Ok(());
    }
}

fn diff(dir1: &AsRef<Path>, dir2: &AsRef<Path>) {
    let status = Command::new("diff")
        .arg("-ru")
        .arg(dir1.as_ref().as_os_str())
        .arg(dir2.as_ref().as_os_str())
        .status()
        .expect("failed to execute `diff'");
    assert!(status.success());
}

unit_tests!{
    fn read_one(f: &CatFSTests) {
        let mut s = String::new();
        File::open(f.mnt.join("dir1/file1")).unwrap().read_to_string(&mut s).unwrap();
        assert_eq!(s, "dir1/file1\n");
    }

    fn read_all(f: &CatFSTests) {
        diff(&CatFSTests::get_orig_dir(), &f.mnt);
    }

    fn create(f: &CatFSTests) {
        {
            let mut fh = OpenOptions::new().write(true).create(true)
                .open(Path::new(&f.mnt).join("foo")).unwrap();
            fh.write_all(b"hello world").unwrap();
        }

        fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        diff(&f.get_from(), &f.mnt);
    }

    fn large_write(f: &CatFSTests) {
        let mut of=OsString::from("of=");
        of.push(f.mnt.join("foo"));
        let status = Command::new("dd")
            .arg("if=/dev/zero").arg(of)
            .arg("bs=1M").arg("count=100")
            .status().expect("failed to execute `dd'");
        assert!(status.success());

        let foo = fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        assert_eq!(foo.len(), 100 * 1024 * 1024);
    }

    fn large_dir(f: &CatFSTests) {
        let dir2 = Path::new(&f.mnt).join("dir2");
        for i in 1..1001 {
            let _fh = OpenOptions::new().write(true).create(true)
                .open(dir2.join(format!("{}", i))).unwrap();
        }

        let mut i = 0;
        let mut total = 0;
        for entry in fs::read_dir(dir2).unwrap() {
            i += 1;
            total += entry.unwrap().file_name().to_str().unwrap().parse().unwrap();
        }
        assert_eq!(i, 1000);
        assert_eq!(total, (1000 * (1000 + 1)) / 2);
    }

    fn read_modify_write(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        {
            let fh = OpenOptions::new().write(true).open(&file1).unwrap();
            let nbytes = fh.write_at("*".as_bytes(), 9).unwrap();
            assert_eq!(nbytes, 1);
        }

        let mut s = String::new();
        File::open(&file1).unwrap().read_to_string(&mut s).unwrap();
        assert_eq!(s, "dir1/file*\n");
    }

    fn unlink(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        fs::remove_file(&file1).unwrap();
        if let Err(e) = fs::symlink_metadata(&file1) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", file1);
        }
    }

    fn read_unlink(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        {
            let mut s = String::new();
            File::open(&file1).unwrap().read_to_string(&mut s).unwrap();
            assert_eq!(s, "dir1/file1\n");
        }
        fs::remove_file(&file1).unwrap();
        if let Err(e) = fs::symlink_metadata(&file1) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", file1);
        }
    }

    fn rmdir(f: &CatFSTests) {
        let dir2 = f.mnt.join("dir2");
        fs::remove_dir(&dir2).unwrap();
        if let Err(e) = fs::symlink_metadata(&dir2) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", dir2);
        }
    }

    fn rmdir_not_empty(f: &CatFSTests) {
        let dir1 = f.mnt.join("dir1");
        if let Err(e) = fs::remove_dir(&dir1) {
            assert_eq!(e.raw_os_error().unwrap(), libc::ENOTEMPTY);
        } else {
            panic!("{:?} deleted", dir1);
        }
    }
}
<commit_msg>create the empty dir test case since git doesn't track emtpy dir<commit_after>#[allow(unused_imports)]
#[macro_use]
extern crate log;
extern crate libc;
extern crate env_logger;
extern crate catfs;
extern crate rand;
extern crate fuse;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Write};
use std::process::Command;
use std::path::{Path, PathBuf};
use std::os::unix::fs::FileExt;

use rand::{thread_rng, Rng};

use catfs::CatFS;
use catfs::catfs::error;

#[macro_use]
mod test_suite;

trait Fixture {
    fn setup() -> error::Result<Self>
    where
        Self: std::marker::Sized;
    fn teardown(self) -> error::Result<()>;
}

struct CatFSTests<'a> {
    prefix: PathBuf,
    mnt: PathBuf,
    src: *const PathBuf,
    cache: *const PathBuf,
    session: Option<fuse::BackgroundSession<'a>>,
}

fn copy_all(dir1: &AsRef<Path>, dir2: &AsRef<Path>) -> error::Result<()> {
    fs::create_dir(dir2)?;

    for entry in fs::read_dir(dir1)? {
        let entry = entry?;
        let to = dir2.as_ref().join(entry.file_name());

        if entry.file_type()?.is_dir() {
            copy_all(&entry.path(), &to)?;
        } else {
            fs::copy(entry.path(), to)?;
        }
    }

    return Ok(());
}

impl<'a> CatFSTests<'a> {
    fn get_orig_dir() -> PathBuf {
        let manifest = env::var_os("CARGO_MANIFEST_DIR").unwrap();
        return PathBuf::from(manifest).join("tests/resources");
    }

    fn get_from(&self) -> PathBuf {
        return self.prefix.join("resources");
    }

    fn extend(&self, s: *const PathBuf) -> &'static PathBuf {
        return unsafe { std::mem::transmute(s) };
    }

    fn mount(&self) -> error::Result<fuse::BackgroundSession<'a>> {
        let src = self.extend(self.src);
        let cache = self.extend(self.cache);
        let fs = CatFS::new(src, cache)?;

        return Ok(unsafe { fuse::spawn_mount(fs, &self.mnt, &[])? });
    }
}

impl<'a> Fixture for CatFSTests<'a> {
    fn setup() -> error::Result<CatFSTests<'a>> {
        #[allow(unused_must_use)] env_logger::init();

        let manifest = env::var_os("CARGO_MANIFEST_DIR").unwrap();
        let prefix = PathBuf::from(manifest).join("target/test").join(
            thread_rng().gen_ascii_chars().take(10).collect::<String>(),
        );
        let mnt = prefix.join("mnt");
        let resources = prefix.join("resources");
        let cache = prefix.join("cache");

        fs::create_dir_all(&mnt)?;
        fs::create_dir_all(&cache)?;

        fs::create_dir(CatFSTests::get_orig_dir().join("dir2"));
        copy_all(&CatFSTests::get_orig_dir(), &resources)?;

        let mut t = CatFSTests {
            prefix: prefix,
            mnt: mnt,
            src: &resources as *const PathBuf,
            cache: &cache as *const PathBuf,
            session: Default::default(),
        };

        std::mem::forget(resources);
        std::mem::forget(cache);

        t.session = Some(t.mount()?);

        return Ok(t);
    }

    fn teardown(self) -> error::Result<()> {
        {
            // move out the session to let us umount first
            #[allow(unused_variables)]
            let session = self.session;
        }
        fs::remove_dir_all(&self.prefix)?;
        // TODO do I need to free self.src/cache?
        return Ok(());
    }
}

fn diff(dir1: &AsRef<Path>, dir2: &AsRef<Path>) {
    let status = Command::new("diff")
        .arg("-ru")
        .arg(dir1.as_ref().as_os_str())
        .arg(dir2.as_ref().as_os_str())
        .status()
        .expect("failed to execute `diff'");
    assert!(status.success());
}

unit_tests!{
    fn read_one(f: &CatFSTests) {
        let mut s = String::new();
        File::open(f.mnt.join("dir1/file1")).unwrap().read_to_string(&mut s).unwrap();
        assert_eq!(s, "dir1/file1\n");
    }

    fn read_all(f: &CatFSTests) {
        diff(&CatFSTests::get_orig_dir(), &f.mnt);
    }

    fn create(f: &CatFSTests) {
        {
            let mut fh = OpenOptions::new().write(true).create(true)
                .open(Path::new(&f.mnt).join("foo")).unwrap();
            fh.write_all(b"hello world").unwrap();
        }

        fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        diff(&f.get_from(), &f.mnt);
    }

    fn large_write(f: &CatFSTests) {
        let mut of=OsString::from("of=");
        of.push(f.mnt.join("foo"));
        let status = Command::new("dd")
            .arg("if=/dev/zero").arg(of)
            .arg("bs=1M").arg("count=100")
            .status().expect("failed to execute `dd'");
        assert!(status.success());

        let foo = fs::symlink_metadata(&f.get_from().join("foo")).unwrap();
        assert_eq!(foo.len(), 100 * 1024 * 1024);
    }

    fn large_dir(f: &CatFSTests) {
        let dir2 = Path::new(&f.mnt).join("dir2");
        for i in 1..1001 {
            let _fh = OpenOptions::new().write(true).create(true)
                .open(dir2.join(format!("{}", i))).unwrap();
        }

        let mut i = 0;
        let mut total = 0;
        for entry in fs::read_dir(dir2).unwrap() {
            i += 1;
            total += entry.unwrap().file_name().to_str().unwrap().parse().unwrap();
        }
        assert_eq!(i, 1000);
        assert_eq!(total, (1000 * (1000 + 1)) / 2);
    }

    fn read_modify_write(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        {
            let fh = OpenOptions::new().write(true).open(&file1).unwrap();
            let nbytes = fh.write_at("*".as_bytes(), 9).unwrap();
            assert_eq!(nbytes, 1);
        }

        let mut s = String::new();
        File::open(&file1).unwrap().read_to_string(&mut s).unwrap();
        assert_eq!(s, "dir1/file*\n");
    }

    fn unlink(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        fs::remove_file(&file1).unwrap();
        if let Err(e) = fs::symlink_metadata(&file1) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", file1);
        }
    }

    fn read_unlink(f: &CatFSTests) {
        let file1 = f.mnt.join("dir1/file1");
        {
            let mut s = String::new();
            File::open(&file1).unwrap().read_to_string(&mut s).unwrap();
            assert_eq!(s, "dir1/file1\n");
        }
        fs::remove_file(&file1).unwrap();
        if let Err(e) = fs::symlink_metadata(&file1) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", file1);
        }
    }

    fn rmdir(f: &CatFSTests) {
        let dir2 = f.mnt.join("dir2");
        fs::remove_dir(&dir2).unwrap();
        if let Err(e) = fs::symlink_metadata(&dir2) {
            assert_eq!(e.kind(), io::ErrorKind::NotFound);
        } else {
            panic!("{:?} still exists", dir2);
        }
    }

    fn rmdir_not_empty(f: &CatFSTests) {
        let dir1 = f.mnt.join("dir1");
        if let Err(e) = fs::remove_dir(&dir1) {
            assert_eq!(e.raw_os_error().unwrap(), libc::ENOTEMPTY);
        } else {
            panic!("{:?} deleted", dir1);
        }
    }
}
<|endoftext|>


<commit_before>use super::{DevPath, Device, DeviceHandler, RawDevice, Surface};

use drm::control::{connector, crtc, encoder, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo};
use drm::Device as BasicDevice;
use nix::libc::dev_t;
use nix::sys::stat::fstat;

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::iter::FromIterator;
use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};

mod surface;
pub use self::surface::LegacyDrmSurface;
use self::surface::{LegacyDrmSurfaceInternal, State};

pub mod error;
use self::error::*;

#[cfg(feature = "backend_session")]
pub mod session;

pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
    dev: Rc<Dev<A>>,
    dev_id: dev_t,
    priviledged: bool,
    active: Arc<AtomicBool>,
    old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>,
    backends: Rc<RefCell<HashMap<crtc::Handle, Weak<LegacyDrmSurfaceInternal<A>>>>>,
    handler: Option<RefCell<Box<DeviceHandler<Device = LegacyDrmDevice<A>>>>>,
    logger: ::slog::Logger,
}

pub(in crate::backend::drm) struct Dev<A: AsRawFd + 'static>(A);
impl<A: AsRawFd + 'static> AsRawFd for Dev<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.0.as_raw_fd()
    }
}
impl<A: AsRawFd + 'static> BasicDevice for Dev<A> {}
impl<A: AsRawFd + 'static> ControlDevice for Dev<A> {}

impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
    /// Create a new `LegacyDrmDevice` from an open drm node
    ///
    /// Returns an error if the file is no valid drm node or context creation was not
    /// successful.
    pub fn new<L>(dev: A, logger: L) -> Result<Self>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm"));

        let dev_id = fstat(dev.as_raw_fd())
            .chain_err(|| ErrorKind::UnableToGetDeviceId)?
            .st_rdev;

        let mut drm = LegacyDrmDevice {
            // Open the drm device and create a context based on that
            dev: Rc::new(Dev(dev)),
            dev_id,
            priviledged: true,
            active: Arc::new(AtomicBool::new(true)),
            old_state: HashMap::new(),
            backends: Rc::new(RefCell::new(HashMap::new())),
            handler: None,
            logger: log.clone(),
        };

        info!(log, "DrmDevice initializing");

        // we want to modeset, so we better be the master, if we run via a tty session
        if drm.set_master().is_err() {
            warn!(log, "Unable to become drm master, assuming unpriviledged mode");
            drm.priviledged = false;
        };

        let res_handles = ControlDevice::resource_handles(&drm).chain_err(|| {
            ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", drm.dev_path()))
        })?;
        for &con in res_handles.connectors() {
            let con_info = connector::Info::load_from_device(&drm, con).chain_err(|| {
                ErrorKind::DrmDev(format!("Error loading connector info on {:?}", drm.dev_path()))
            })?;
            if let Some(enc) = con_info.current_encoder() {
                let enc_info = encoder::Info::load_from_device(&drm, enc).chain_err(|| {
                    ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", drm.dev_path()))
                })?;
                if let Some(crtc) = enc_info.current_crtc() {
                    let info = crtc::Info::load_from_device(&drm, crtc).chain_err(|| {
                        ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", drm.dev_path()))
                    })?;
                    drm.old_state
                        .entry(crtc)
                        .or_insert((info, Vec::new()))
                        .1
                        .push(con);
                }
            }
        }

        Ok(drm)
    }
}

impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmDevice<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.dev.0.as_raw_fd()
    }
}

impl<A: AsRawFd + 'static> BasicDevice for LegacyDrmDevice<A> {}
impl<A: AsRawFd + 'static> ControlDevice for LegacyDrmDevice<A> {}

impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
    type Surface = LegacyDrmSurface<A>;

    fn device_id(&self) -> dev_t {
        self.dev_id
    }

    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static) {
        self.handler = Some(RefCell::new(Box::new(handler)));
    }

    fn clear_handler(&mut self) {
        let _ = self.handler.take();
    }

    fn create_surface(
        &mut self,
        crtc: crtc::Handle,
        mode: Mode,
        connectors: impl IntoIterator<Item = connector::Handle>,
    ) -> Result<LegacyDrmSurface<A>> {
        if self.backends.borrow().contains_key(&crtc) {
            bail!(ErrorKind::CrtcAlreadyInUse(crtc));
        }

        if !self.active.load(Ordering::SeqCst) {
            bail!(ErrorKind::DeviceInactive);
        }

        let connectors = HashSet::from_iter(connectors);
        // check if we have an encoder for every connector and the mode mode
        for connector in &connectors {
            let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| {
                ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path()))
            })?;

            // check the mode
            if !con_info.modes().contains(&mode) {
                bail!(ErrorKind::ModeNotSuitable(mode));
            }

            // check for every connector which encoders it does support
            let encoders = con_info
                .encoders()
                .iter()
                .map(|encoder| {
                    encoder::Info::load_from_device(self, *encoder).chain_err(|| {
                        ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path()))
                    })
                }).collect::<Result<Vec<encoder::Info>>>()?;

            // and if any encoder supports the selected crtc
            let resource_handles = ControlDevice::resource_handles(self).chain_err(|| {
                ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path()))
            })?;
            if !encoders
                .iter()
                .map(|encoder| encoder.possible_crtcs())
                .any(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&crtc))
            {
                bail!(ErrorKind::NoSuitableEncoder(con_info, crtc))
            }
        }

        // configuration is valid, the kernel will figure out the rest
        let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc)));

        let state = State { mode, connectors };

        let backend = Rc::new(LegacyDrmSurfaceInternal {
            dev: self.dev.clone(),
            crtc,
            state: RwLock::new(state.clone()),
            pending: RwLock::new(state),
            logger,
        });

        self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend));
        Ok(LegacyDrmSurface(backend))
    }

    fn process_events(&mut self) {
        match crtc::receive_events(self) {
            Ok(events) => for event in events {
                if let crtc::Event::PageFlip(event) = event {
                    if self.active.load(Ordering::SeqCst) {
                        if self
                            .backends
                            .borrow()
                            .get(&event.crtc)
                            .iter()
                            .flat_map(|x| x.upgrade())
                            .next()
                            .is_some()
                        {
                            trace!(self.logger, "Handling event for backend {:?}", event.crtc);
                            if let Some(handler) = self.handler.as_ref() {
                                handler.borrow_mut().vblank(event.crtc);
                            }
                        } else {
                            self.backends.borrow_mut().remove(&event.crtc);
                        }
                    }
                }
            },
            Err(err) => if let Some(handler) = self.handler.as_ref() {
                handler.borrow_mut().error(
                    ResultExt::<()>::chain_err(Err(err), || {
                        ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path()))
                    }).unwrap_err(),
                );
            },
        }
    }

    fn resource_info<T: ResourceInfo>(&self, handle: T::Handle) -> Result<T> {
        T::load_from_device(self, handle)
            .chain_err(|| ErrorKind::DrmDev(format!("Error loading resource info on {:?}", self.dev_path())))
    }

    fn resource_handles(&self) -> Result<ResourceHandles> {
        ControlDevice::resource_handles(self)
            .chain_err(|| ErrorKind::DrmDev(format!("Error loading resource info on {:?}", self.dev_path())))
    }
}

impl<A: AsRawFd + 'static> RawDevice for LegacyDrmDevice<A> {
    type Surface = LegacyDrmSurface<A>;
}

impl<A: AsRawFd + 'static> Drop for LegacyDrmDevice<A> {
    fn drop(&mut self) {
        self.backends.borrow_mut().clear();
        if Rc::strong_count(&self.dev) > 1 {
            panic!("Pending DrmBackends. You need to free all backends before the DrmDevice gets destroyed");
        }
        if self.active.load(Ordering::SeqCst) {
            for (handle, (info, connectors)) in self.old_state.drain() {
                if let Err(err) = crtc::set(
                    &*self.dev,
                    handle,
                    info.fb(),
                    &connectors,
                    info.position(),
                    info.mode(),
                ) {
                    error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err);
                }
            }
            if self.priviledged {
                if let Err(err) = self.drop_master() {
                    error!(self.logger, "Failed to drop drm master state. Error: {}", err);
                }
            }
        }
    }
}
<commit_msg>drm: fix dropping master when killed from another tty<commit_after>use super::{DevPath, Device, DeviceHandler, RawDevice, Surface};

use drm::control::{connector, crtc, encoder, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo};
use drm::Device as BasicDevice;
use nix::libc::dev_t;
use nix::sys::stat::fstat;

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::iter::FromIterator;
use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock};

mod surface;
pub use self::surface::LegacyDrmSurface;
use self::surface::{LegacyDrmSurfaceInternal, State};

pub mod error;
use self::error::*;

#[cfg(feature = "backend_session")]
pub mod session;

pub struct LegacyDrmDevice<A: AsRawFd + 'static> {
    dev: Rc<Dev<A>>,
    dev_id: dev_t,
    priviledged: bool,
    active: Arc<AtomicBool>,
    old_state: HashMap<crtc::Handle, (crtc::Info, Vec<connector::Handle>)>,
    backends: Rc<RefCell<HashMap<crtc::Handle, Weak<LegacyDrmSurfaceInternal<A>>>>>,
    handler: Option<RefCell<Box<DeviceHandler<Device = LegacyDrmDevice<A>>>>>,
    logger: ::slog::Logger,
}

pub(in crate::backend::drm) struct Dev<A: AsRawFd + 'static>(A);
impl<A: AsRawFd + 'static> AsRawFd for Dev<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.0.as_raw_fd()
    }
}
impl<A: AsRawFd + 'static> BasicDevice for Dev<A> {}
impl<A: AsRawFd + 'static> ControlDevice for Dev<A> {}

impl<A: AsRawFd + 'static> LegacyDrmDevice<A> {
    /// Create a new `LegacyDrmDevice` from an open drm node
    ///
    /// Returns an error if the file is no valid drm node or context creation was not
    /// successful.
    pub fn new<L>(dev: A, logger: L) -> Result<Self>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "backend_drm"));

        let dev_id = fstat(dev.as_raw_fd())
            .chain_err(|| ErrorKind::UnableToGetDeviceId)?
            .st_rdev;

        let mut drm = LegacyDrmDevice {
            // Open the drm device and create a context based on that
            dev: Rc::new(Dev(dev)),
            dev_id,
            priviledged: true,
            active: Arc::new(AtomicBool::new(true)),
            old_state: HashMap::new(),
            backends: Rc::new(RefCell::new(HashMap::new())),
            handler: None,
            logger: log.clone(),
        };

        info!(log, "DrmDevice initializing");

        // we want to modeset, so we better be the master, if we run via a tty session
        if drm.set_master().is_err() {
            warn!(log, "Unable to become drm master, assuming unpriviledged mode");
            drm.priviledged = false;
        };

        let res_handles = ControlDevice::resource_handles(&drm).chain_err(|| {
            ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", drm.dev_path()))
        })?;
        for &con in res_handles.connectors() {
            let con_info = connector::Info::load_from_device(&drm, con).chain_err(|| {
                ErrorKind::DrmDev(format!("Error loading connector info on {:?}", drm.dev_path()))
            })?;
            if let Some(enc) = con_info.current_encoder() {
                let enc_info = encoder::Info::load_from_device(&drm, enc).chain_err(|| {
                    ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", drm.dev_path()))
                })?;
                if let Some(crtc) = enc_info.current_crtc() {
                    let info = crtc::Info::load_from_device(&drm, crtc).chain_err(|| {
                        ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", drm.dev_path()))
                    })?;
                    drm.old_state
                        .entry(crtc)
                        .or_insert((info, Vec::new()))
                        .1
                        .push(con);
                }
            }
        }

        Ok(drm)
    }
}

impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmDevice<A> {
    fn as_raw_fd(&self) -> RawFd {
        self.dev.0.as_raw_fd()
    }
}

impl<A: AsRawFd + 'static> BasicDevice for LegacyDrmDevice<A> {}
impl<A: AsRawFd + 'static> ControlDevice for LegacyDrmDevice<A> {}

impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
    type Surface = LegacyDrmSurface<A>;

    fn device_id(&self) -> dev_t {
        self.dev_id
    }

    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static) {
        self.handler = Some(RefCell::new(Box::new(handler)));
    }

    fn clear_handler(&mut self) {
        let _ = self.handler.take();
    }

    fn create_surface(
        &mut self,
        crtc: crtc::Handle,
        mode: Mode,
        connectors: impl IntoIterator<Item = connector::Handle>,
    ) -> Result<LegacyDrmSurface<A>> {
        if self.backends.borrow().contains_key(&crtc) {
            bail!(ErrorKind::CrtcAlreadyInUse(crtc));
        }

        if !self.active.load(Ordering::SeqCst) {
            bail!(ErrorKind::DeviceInactive);
        }

        let connectors = HashSet::from_iter(connectors);
        // check if we have an encoder for every connector and the mode mode
        for connector in &connectors {
            let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| {
                ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path()))
            })?;

            // check the mode
            if !con_info.modes().contains(&mode) {
                bail!(ErrorKind::ModeNotSuitable(mode));
            }

            // check for every connector which encoders it does support
            let encoders = con_info
                .encoders()
                .iter()
                .map(|encoder| {
                    encoder::Info::load_from_device(self, *encoder).chain_err(|| {
                        ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path()))
                    })
                }).collect::<Result<Vec<encoder::Info>>>()?;

            // and if any encoder supports the selected crtc
            let resource_handles = ControlDevice::resource_handles(self).chain_err(|| {
                ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path()))
            })?;
            if !encoders
                .iter()
                .map(|encoder| encoder.possible_crtcs())
                .any(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&crtc))
            {
                bail!(ErrorKind::NoSuitableEncoder(con_info, crtc))
            }
        }

        // configuration is valid, the kernel will figure out the rest
        let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc)));

        let state = State { mode, connectors };

        let backend = Rc::new(LegacyDrmSurfaceInternal {
            dev: self.dev.clone(),
            crtc,
            state: RwLock::new(state.clone()),
            pending: RwLock::new(state),
            logger,
        });

        self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend));
        Ok(LegacyDrmSurface(backend))
    }

    fn process_events(&mut self) {
        match crtc::receive_events(self) {
            Ok(events) => for event in events {
                if let crtc::Event::PageFlip(event) = event {
                    if self.active.load(Ordering::SeqCst) {
                        if self
                            .backends
                            .borrow()
                            .get(&event.crtc)
                            .iter()
                            .flat_map(|x| x.upgrade())
                            .next()
                            .is_some()
                        {
                            trace!(self.logger, "Handling event for backend {:?}", event.crtc);
                            if let Some(handler) = self.handler.as_ref() {
                                handler.borrow_mut().vblank(event.crtc);
                            }
                        } else {
                            self.backends.borrow_mut().remove(&event.crtc);
                        }
                    }
                }
            },
            Err(err) => if let Some(handler) = self.handler.as_ref() {
                handler.borrow_mut().error(
                    ResultExt::<()>::chain_err(Err(err), || {
                        ErrorKind::DrmDev(format!("Error processing drm events on {:?}", self.dev_path()))
                    }).unwrap_err(),
                );
            },
        }
    }

    fn resource_info<T: ResourceInfo>(&self, handle: T::Handle) -> Result<T> {
        T::load_from_device(self, handle)
            .chain_err(|| ErrorKind::DrmDev(format!("Error loading resource info on {:?}", self.dev_path())))
    }

    fn resource_handles(&self) -> Result<ResourceHandles> {
        ControlDevice::resource_handles(self)
            .chain_err(|| ErrorKind::DrmDev(format!("Error loading resource info on {:?}", self.dev_path())))
    }
}

impl<A: AsRawFd + 'static> RawDevice for LegacyDrmDevice<A> {
    type Surface = LegacyDrmSurface<A>;
}

impl<A: AsRawFd + 'static> Drop for LegacyDrmDevice<A> {
    fn drop(&mut self) {
        self.backends.borrow_mut().clear();
        if Rc::strong_count(&self.dev) > 1 {
            panic!("Pending DrmBackends. You need to free all backends before the DrmDevice gets destroyed");
        }
        if self.active.load(Ordering::SeqCst) {
            for (handle, (info, connectors)) in self.old_state.drain() {
                if let Err(err) = crtc::set(
                    &*self.dev,
                    handle,
                    info.fb(),
                    &connectors,
                    info.position(),
                    info.mode(),
                ) {
                    error!(self.logger, "Failed to reset crtc ({:?}). Error: {}", handle, err);
                }
            }
        }
        if self.priviledged {
            if let Err(err) = self.drop_master() {
                error!(self.logger, "Failed to drop drm master state. Error: {}", err);
            }
        }
    }
}
<|endoftext|>