1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright (c) 2017-present, PingCAP, Inc. Licensed under Apache-2.0.

use std::io::{Read, Result as IoResult, Seek, SeekFrom, Write};
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use crate::env::{DefaultFileSystem, FileSystem, Permission, WriteExt};

pub struct ObfuscatedReader(<DefaultFileSystem as FileSystem>::Reader);

impl Read for ObfuscatedReader {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        if !buf.is_empty() {
            let len = self.0.read(&mut buf[..1])?;
            if len == 1 {
                buf[0] = buf[0].wrapping_sub(1);
            }
            Ok(len)
        } else {
            Ok(0)
        }
    }
}

impl Seek for ObfuscatedReader {
    fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
        self.0.seek(pos)
    }
}

pub struct ObfuscatedWriter(<DefaultFileSystem as FileSystem>::Writer);

impl Write for ObfuscatedWriter {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        if !buf.is_empty() {
            let tmp_vec = vec![buf[0].wrapping_add(1)];
            self.0.write(&tmp_vec)
        } else {
            Ok(0)
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        self.0.flush()
    }
}

impl Seek for ObfuscatedWriter {
    fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
        self.0.seek(pos)
    }
}

impl WriteExt for ObfuscatedWriter {
    fn truncate(&mut self, offset: usize) -> IoResult<()> {
        self.0.truncate(offset)
    }

    fn allocate(&mut self, offset: usize, size: usize) -> IoResult<()> {
        self.0.allocate(offset, size)
    }
}

/// `[ObfuscatedFileSystem]` is a special implementation of `[FileSystem]`,
/// which is used for constructing and simulating an abnormal file system for
/// `[Read]` and `[Write]`.
pub struct ObfuscatedFileSystem {
    inner: DefaultFileSystem,
    files: AtomicUsize,
}

impl Default for ObfuscatedFileSystem {
    fn default() -> Self {
        ObfuscatedFileSystem {
            inner: DefaultFileSystem,
            files: AtomicUsize::new(0),
        }
    }
}

impl ObfuscatedFileSystem {
    pub fn file_count(&self) -> usize {
        self.files.load(Ordering::Relaxed)
    }
}

impl FileSystem for ObfuscatedFileSystem {
    type Handle = <DefaultFileSystem as FileSystem>::Handle;
    type Reader = ObfuscatedReader;
    type Writer = ObfuscatedWriter;

    fn create<P: AsRef<Path>>(&self, path: P) -> IoResult<Self::Handle> {
        let r = self.inner.create(path);
        if r.is_ok() {
            self.files.fetch_add(1, Ordering::Relaxed);
        }
        r
    }

    fn open<P: AsRef<Path>>(&self, path: P, perm: Permission) -> IoResult<Self::Handle> {
        self.inner.open(path, perm)
    }

    fn delete<P: AsRef<Path>>(&self, path: P) -> IoResult<()> {
        let r = self.inner.delete(path);
        if r.is_ok() {
            self.files.fetch_sub(1, Ordering::Relaxed);
        }
        r
    }

    fn rename<P: AsRef<Path>>(&self, src_path: P, dst_path: P) -> IoResult<()> {
        self.inner.rename(src_path, dst_path)
    }

    fn reuse<P: AsRef<Path>>(&self, src_path: P, dst_path: P) -> IoResult<()> {
        self.delete(src_path)?;
        self.create(dst_path)?;
        Ok(())
    }

    fn new_reader(&self, handle: Arc<Self::Handle>) -> IoResult<Self::Reader> {
        Ok(ObfuscatedReader(self.inner.new_reader(handle)?))
    }

    fn new_writer(&self, handle: Arc<Self::Handle>) -> IoResult<Self::Writer> {
        Ok(ObfuscatedWriter(self.inner.new_writer(handle)?))
    }
}