├── Cargo.toml ├── README.md ├── src ├── main.rs ├── s3util.rs └── s3fs.rs └── Cargo.lock /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rusty-s3fs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | opendal = "0.30.4" 10 | fuser = "0.12.0" 11 | libc = "0.2.51" 12 | env_logger = "0.9" 13 | clap = { version = "3.0", features = ["cargo", "derive"] } 14 | serde = { version = "1.0.102", features = ["std", "derive"] } 15 | log = "0.4.6" 16 | bincode = "1.3.1" 17 | tokio = { version = "1.27.0", features = ["full"] } 18 | time = "0.3.0" 19 | futures = "0.3" 20 | async-recursion = "1.0.4" 21 | anyhow = { version = "1.0", default-features = false } 22 | rayon = "1.5" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rusty-s3fs 2 | 3 | 4 | 5 | ## About 6 | 7 | A rust implementation for object storage FUSE, was for AWS s3, currently focus on Google Storage Services. Aims for accelerating model downloading (cold starting) time for LLM serving engine. 8 | 9 | 10 | 11 | ## Dependencies 12 | 13 | FUSE must be installed to build or run programs that use FUSE-Rust (i.e. kernel driver and libraries. Some platforms may also require userland utils like `fusermount`). A default installation of FUSE is usually sufficient. 14 | 15 | To build FUSE-Rust or any program that depends on it, `pkg-config` needs to be installed as well. 16 | 17 | ### Linux 18 | 19 | [FUSE for Linux](https://github.com/libfuse/libfuse/) is available in most Linux distributions and usually called `fuse` or `fuse3` (this crate is compatible with both). To install on a Debian based system: 20 | 21 | ``` 22 | sudo apt-get install fuse 23 | ``` 24 | 25 | Install on CentOS: 26 | 27 | ``` 28 | sudo yum install fuse 29 | ``` 30 | 31 | To build, FUSE libraries and headers are required. The package is usually called `libfuse-dev` or `fuse-devel`. Also `pkg-config` is required for locating libraries and headers. 32 | 33 | ``` 34 | sudo apt-get install libfuse-dev pkg-config 35 | sudo yum install fuse-devel pkgconfig 36 | ``` 37 | 38 | ### macOS 39 | 40 | Installer packages can be downloaded from the [FUSE for macOS homepage](https://osxfuse.github.io/). This is the *kernel* part that needs to be installed always. 41 | 42 | ### FreeBSD 43 | 44 | Install packages `fusefs-libs` and `pkgconf`. 45 | 46 | ``` 47 | pkg install fusefs-libs pkgconf 48 | ``` 49 | 50 | 51 | 52 | ## Getting started 53 | 54 | First, clone the repo and cd to it 55 | 56 | ``` 57 | git clone https://github.com/Kaiyang-Chen/rusty-s3fs.git 58 | cd rusty-s3fs 59 | ``` 60 | 61 | Second, build it with 62 | 63 | ``` 64 | cargo build 65 | ``` 66 | 67 | Last, run it with 68 | 69 | ``` 70 | ./target/debug/rusty-s3fs 71 | --mount-point MOUNT_POINT 72 | --bucket-name BUCKET_NAME 73 | --data-dir CACHE_DATA_DIRECTORY 74 | --auto_unmount 75 | --allow-root 76 | --direct-io 77 | ``` 78 | 79 | - `mount-point` is the directory path of your mount point 80 | - `bucket-name` is the name of cloud object storage bucket that you want to mount 81 | - `data-dir` is the real data directory on your local filesystem to cache your read from cloud, default to be `/tmp/fuser` 82 | - `auto-unmount` is the option stating whether you want to auto unmount the bucket when the program exists 83 | - `allow-root` is the option stating whether your mount filesystem can be accessed by root 84 | - `direct-io` is the option stating whether you want to open your file with `FOPEN_DIRECT_IO` flag 85 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod s3fs; 2 | mod s3util; 3 | use fuser; 4 | use clap::{crate_version, Arg, Command}; 5 | use std::env; 6 | use std::io::ErrorKind; 7 | use fuser::MountOption; 8 | use log::error; 9 | use crate::s3fs::S3FS; 10 | use crate::s3util::GcsWorker; 11 | 12 | 13 | 14 | fn main() { 15 | let matches = Command::new("S3-Fuse") 16 | .version(crate_version!()) 17 | .author("Kaiyang Chen") 18 | .arg( 19 | Arg::new("data-dir") 20 | .long("data-dir") 21 | .value_name("DIR") 22 | .default_value("/tmp/fuser") 23 | .help("Set local directory used to store data") 24 | .takes_value(true), 25 | ) 26 | .arg( 27 | Arg::new("mount-point") 28 | .long("mount-point") 29 | .short('m') 30 | .value_name("MOUNT_POINT") 31 | .required(true) 32 | .help("Act as a client, and mount FUSE at given path"), 33 | ) 34 | .arg( 35 | Arg::new("bucket-name") 36 | .long("bucket-name") 37 | .value_name("bucket_name") 38 | .short('b') 39 | .required(true) 40 | .help("Set the object storage bucket name"), 41 | ) 42 | .arg( 43 | Arg::new("auto_unmount") 44 | .long("auto_unmount") 45 | .help("Automatically unmount on process exit"), 46 | ) 47 | .arg( 48 | Arg::new("allow-root") 49 | .long("allow-root") 50 | .help("Allow root user to access filesystem"), 51 | ) 52 | .arg( 53 | Arg::new("direct-io") 54 | .long("direct-io") 55 | .requires("mount-point") 56 | .help("Mount FUSE with direct IO"), 57 | ) 58 | .get_matches(); 59 | env_logger::init(); 60 | let mountpoint: String = matches 61 | .value_of("mount-point") 62 | .unwrap_or_default() 63 | .to_string(); 64 | let bucket: String = matches 65 | .value_of("bucket-name") 66 | .unwrap() 67 | .to_string(); 68 | let mut options = vec![MountOption::RW, MountOption::FSName("s3-fuse".to_string())]; 69 | // if let Ok(enabled) = S3FS::fuse_allow_other_enabled() { 70 | // if enabled { 71 | // options.push(MountOption::AllowOther); 72 | // } 73 | // } else { 74 | // eprintln!("Unable to read /etc/fuse.conf"); 75 | // }; 76 | if matches.is_present("auto_unmount") { 77 | options.push(MountOption::AutoUnmount); 78 | } 79 | if matches.is_present("allow-root") { 80 | options.push(MountOption::AllowRoot); 81 | } 82 | let data_dir: String = matches.value_of("data-dir").unwrap_or_default().to_string(); 83 | let result = fuser::mount2( 84 | S3FS::new( 85 | data_dir, 86 | matches.is_present("direct-io"), 87 | GcsWorker::new(bucket) 88 | ), 89 | mountpoint, 90 | &options, 91 | ); 92 | if let Err(e) = result { 93 | // Return a special error code for permission denied, which usually indicates that 94 | // "user_allow_other" is missing from /etc/fuse.conf 95 | if e.kind() == ErrorKind::PermissionDenied { 96 | error!("{}", e.to_string()); 97 | std::process::exit(2); 98 | } 99 | } 100 | 101 | } -------------------------------------------------------------------------------- /src/s3util.rs: -------------------------------------------------------------------------------- 1 | use opendal::Operator; 2 | use opendal::services::Gcs; 3 | use opendal::Metadata; 4 | use futures::TryStreamExt; 5 | use std::sync::Arc; 6 | // use std::task::{Context, Poll}; 7 | // use futures::future::poll_fn; 8 | // use opendal::raw::oio::Read; 9 | // use std::ops::RangeBounds; 10 | // use std::error::Error; 11 | use tokio::sync::{Mutex, Semaphore}; 12 | use tokio::fs::File; 13 | use tokio::io::{AsyncSeekExt, AsyncWriteExt, SeekFrom}; 14 | use tokio::task; 15 | // use tokio::runtime::Runtime; 16 | 17 | pub(crate) struct GcsWorker { 18 | bucket: String, 19 | builder: Gcs, 20 | } 21 | 22 | impl GcsWorker { 23 | pub fn new( 24 | bucket: String, 25 | ) -> GcsWorker { 26 | let mut builder = Gcs::default(); 27 | builder.bucket(bucket.as_str()); 28 | // builder.endpoint("http://127.0.0.1:9000"); 29 | // builder.access_key_id("admin"); 30 | // builder.secret_access_key("password"); 31 | GcsWorker { 32 | bucket, 33 | builder, 34 | } 35 | } 36 | 37 | pub async fn is_exist(&self, path: &str) -> Result> { 38 | let op = Operator::new(self.builder.clone())?.finish(); 39 | let exist = op.is_exist(path).await?; 40 | Ok(exist) 41 | } 42 | 43 | pub async fn get_stats(&self, path: &str) -> Result> { 44 | let op = Operator::new(self.builder.clone())?.finish(); 45 | let metadata = op.stat(path).await?; 46 | Ok(metadata) 47 | } 48 | 49 | pub async fn is_file(&self, path: &str) -> Result> { 50 | let op = Operator::new(self.builder.clone())?.finish(); 51 | let metadata = op.stat(path).await?; 52 | if metadata.is_file(){ 53 | Ok(true) 54 | } else { 55 | Ok(false) 56 | } 57 | 58 | } 59 | 60 | // pub async fn get_data(&self, path: &str) -> Result, Box> { 61 | // let op = Operator::new(self.builder.clone())?.finish(); 62 | 63 | // // Get the metadata and file size 64 | // let metadata = op.stat(path).await?; 65 | // let size = metadata.content_length(); 66 | 67 | // // Create a buffer to hold the data in memory temporarily 68 | // let mut data = Vec::new(); 69 | 70 | // // Define the read block size 71 | // let block_size: usize = 512 * 1024 * 1024; 72 | 73 | // // Create a buffer outside the loop to increase efficiency 74 | // let mut buffer = vec![0; block_size]; 75 | 76 | // // Read the remote file in chunks using range_reader 77 | // for offset in (0..size).step_by(block_size) { 78 | // let end = std::cmp::min(offset + block_size as u64, size); 79 | 80 | // // Read a range of data from the remote file 81 | // let mut range_reader = op.range_reader(path, offset..end).await?; 82 | 83 | // // Resize the buffer if the last chunk is smaller than the block size 84 | // if end - offset < block_size as u64 { 85 | // buffer.resize((end - offset) as usize, 0); 86 | // } 87 | 88 | // // Read the data from the range reader into the buffer using poll_read 89 | // let mut bytes_read = 0; 90 | // while bytes_read < buffer.len() { 91 | // let poll_result = poll_fn(|cx: &mut Context<'_>| range_reader.poll_read(cx, &mut buffer[bytes_read..])).await; 92 | // match poll_result { 93 | // Ok(n) => { 94 | // if n == 0 { 95 | // break; 96 | // } 97 | // bytes_read += n; 98 | // } 99 | // Err(e) => return Err(Box::new(e)) 100 | // } 101 | // } 102 | 103 | // // Append the read data to the `data` Vec 104 | // data.extend_from_slice(&buffer[0..bytes_read]); 105 | // } 106 | 107 | // Ok(data) 108 | // } 109 | 110 | 111 | pub async fn get_data( 112 | &self, 113 | path: &str, 114 | local_file_path: &str, 115 | ) -> Result { 116 | let op = Operator::new(self.builder.clone())?.finish(); 117 | let metadata = op.stat(path).await?; 118 | let size = metadata.content_length(); 119 | 120 | // Create and initialize the file 121 | let file = File::create(local_file_path).await?; 122 | file.set_len(size).await?; 123 | let file_mutex = Arc::new(Mutex::new(file)); 124 | let block_size = 64 * 1024 * 1024; 125 | let num_blocks = (size as f64 / block_size as f64).ceil() as usize; 126 | let num_threads = 4; 127 | let semaphore = Arc::new(Semaphore::new(num_threads)); 128 | let mut tasks = Vec::with_capacity(num_blocks); 129 | let builder_clone = self.builder.clone(); 130 | for i in 0..num_blocks { 131 | let start = block_size * i as u64; 132 | let end = std::cmp::min(start + block_size, size); 133 | let range = start..end; 134 | let semaphore_clone = Arc::clone(&semaphore); 135 | let path_clone = path.to_owned(); 136 | let file_clone = Arc::clone(&file_mutex); 137 | let builder_clone = builder_clone.clone(); 138 | let task = task::spawn(async move { 139 | let _permit = semaphore_clone.acquire().await; 140 | let op_c = Operator::new(builder_clone)?.finish(); 141 | 142 | let data = op_c.range_read(&path_clone, range).await?; 143 | let mut file_clone = file_clone.lock().await; 144 | file_clone.seek(SeekFrom::Start(start)).await?; 145 | file_clone.write_all(&data).await?; 146 | 147 | Ok::<(), anyhow::Error>(()) 148 | }); 149 | 150 | tasks.push(task); 151 | } 152 | 153 | let mut total_bytes_read: u64 = 0; 154 | for result in futures::future::join_all(tasks).await { 155 | match result { 156 | Ok(_) => total_bytes_read += block_size, 157 | Err(e) => return Err(e.into()), 158 | } 159 | } 160 | // Return the total bytes read 161 | Ok(total_bytes_read) 162 | } 163 | 164 | 165 | 166 | 167 | 168 | pub async fn list_dir(&self, path: &str) -> Result, Box>{ 169 | let op = Operator::new(self.builder.clone())?.finish(); 170 | let mut ds = op.list(path).await?; 171 | let mut filenames = Vec::new(); 172 | 173 | while let Some(de) = ds.try_next().await? { 174 | filenames.push(de.name().to_string()); 175 | } 176 | Ok(filenames) 177 | } 178 | } -------------------------------------------------------------------------------- /src/s3fs.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::time::{Duration, SystemTime, UNIX_EPOCH}; 3 | use std::ffi::OsStr; 4 | use fuser; 5 | use std::{io, fs}; 6 | use std::path::{Path, PathBuf}; 7 | use std::fs::{File, OpenOptions}; 8 | use std::io::{BufRead, BufReader, Seek, Write, SeekFrom}; 9 | use fuser::{ 10 | Filesystem, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, 11 | Request, KernelConfig, FUSE_ROOT_ID, ReplyOpen, ReplyWrite, ReplyCreate, ReplyEmpty 12 | }; 13 | use fuser::consts::FOPEN_DIRECT_IO; 14 | use std::sync::atomic::{AtomicU64, Ordering}; 15 | use std::os::raw::c_int; 16 | use std::collections::BTreeMap; 17 | use std::os::unix::ffi::OsStrExt; 18 | use log::debug; 19 | use std::cmp::min; 20 | use std::os::unix::fs::FileExt; 21 | use crate::s3util::GcsWorker; 22 | use tokio::runtime::Runtime; 23 | use time::OffsetDateTime; 24 | use async_recursion::async_recursion; 25 | 26 | 27 | const BLOCK_SIZE: u64 = 512; 28 | const MAX_NAME_LENGTH: u32 = 255; 29 | const FMODE_EXEC: i32 = 0x20; 30 | // Top two file handle bits are used to store permissions 31 | // Note: This isn't safe, since the client can modify those bits. 32 | const FILE_HANDLE_READ_BIT: u64 = 1 << 63; 33 | const FILE_HANDLE_WRITE_BIT: u64 = 1 << 62; 34 | type Inode = u64; 35 | type DirectoryDescriptor = BTreeMap, (Inode, FileKind)>; 36 | 37 | #[derive(Serialize, Deserialize, Copy, Clone, PartialEq)] 38 | enum FileKind { 39 | File, 40 | Directory, 41 | } 42 | 43 | impl From for fuser::FileType { 44 | fn from(kind: FileKind) -> Self { 45 | match kind { 46 | FileKind::File => fuser::FileType::RegularFile, 47 | FileKind::Directory => fuser::FileType::Directory, 48 | } 49 | } 50 | } 51 | 52 | fn system_time_from_time(secs: i64, nsecs: u32) -> SystemTime { 53 | if secs >= 0 { 54 | UNIX_EPOCH + Duration::new(secs as u64, nsecs) 55 | } else { 56 | UNIX_EPOCH - Duration::new((-secs) as u64, nsecs) 57 | } 58 | } 59 | 60 | fn time_now() -> (i64, u32) { 61 | time_from_system_time(&SystemTime::now()) 62 | } 63 | 64 | fn time_from_system_time(system_time: &SystemTime) -> (i64, u32) { 65 | // Convert to signed 64-bit time with epoch at 0 66 | match system_time.duration_since(UNIX_EPOCH) { 67 | Ok(duration) => (duration.as_secs() as i64, duration.subsec_nanos()), 68 | Err(before_epoch_error) => ( 69 | -(before_epoch_error.duration().as_secs() as i64), 70 | before_epoch_error.duration().subsec_nanos(), 71 | ), 72 | } 73 | } 74 | 75 | #[derive(Serialize, Deserialize)] 76 | struct InodeAttributes { 77 | pub inode: Inode, 78 | pub open_file_handles: u64, // Ref count of open file handles to this inode 79 | pub size: u64, 80 | pub last_accessed: (i64, u32), 81 | pub last_modified: (i64, u32), 82 | pub last_metadata_changed: (i64, u32), 83 | pub kind: FileKind, 84 | // Permissions and special mode bits 85 | pub mode: u16, 86 | pub hardlinks: u32, 87 | pub uid: u32, 88 | pub gid: u32, 89 | pub md5: String 90 | } 91 | 92 | impl From for fuser::FileAttr { 93 | fn from(attrs: InodeAttributes) -> Self { 94 | fuser::FileAttr { 95 | ino: attrs.inode, 96 | size: attrs.size, 97 | blocks: (attrs.size + BLOCK_SIZE - 1) / BLOCK_SIZE, 98 | atime: system_time_from_time(attrs.last_accessed.0, attrs.last_accessed.1), 99 | mtime: system_time_from_time(attrs.last_modified.0, attrs.last_modified.1), 100 | ctime: system_time_from_time( 101 | attrs.last_metadata_changed.0, 102 | attrs.last_metadata_changed.1, 103 | ), 104 | crtime: SystemTime::UNIX_EPOCH, 105 | kind: attrs.kind.into(), 106 | perm: attrs.mode, 107 | nlink: attrs.hardlinks, 108 | uid: attrs.uid, 109 | gid: attrs.gid, 110 | rdev: 0, 111 | blksize: BLOCK_SIZE as u32, 112 | flags: 0, 113 | } 114 | } 115 | } 116 | 117 | // Stores inode metadata data in "$data_dir/inodes" and file contents in "$data_dir/contents" 118 | // Directory data is stored in the file's contents, as a serialized DirectoryDescriptor 119 | pub(crate) struct S3FS { 120 | data_dir: String, 121 | next_file_handle: AtomicU64, 122 | direct_io: bool, 123 | worker: GcsWorker, 124 | } 125 | 126 | impl S3FS { 127 | pub fn new( 128 | data_dir: String, 129 | direct_io: bool, 130 | worker: GcsWorker, 131 | ) -> S3FS { 132 | S3FS { 133 | data_dir, 134 | next_file_handle: AtomicU64::new(1), 135 | direct_io, 136 | worker, 137 | } 138 | } 139 | 140 | pub fn fuse_allow_other_enabled() -> io::Result { 141 | let file = File::open("/etc/fuse.conf")?; 142 | for line in BufReader::new(file).lines() { 143 | if line?.trim_start().starts_with("user_allow_other") { 144 | return Ok(true); 145 | } 146 | } 147 | Ok(false) 148 | } 149 | 150 | fn allocate_next_file_handle(&self, read: bool, write: bool) -> u64 { 151 | let mut fh = self.next_file_handle.fetch_add(1, Ordering::SeqCst); 152 | // Assert that we haven't run out of file handles 153 | assert!(fh < FILE_HANDLE_WRITE_BIT && fh < FILE_HANDLE_READ_BIT); 154 | if read { 155 | fh |= FILE_HANDLE_READ_BIT; 156 | } 157 | if write { 158 | fh |= FILE_HANDLE_WRITE_BIT; 159 | } 160 | 161 | fh 162 | } 163 | 164 | fn allocate_next_inode(&self) -> Inode { 165 | let path = Path::new(&self.data_dir).join("superblock"); 166 | let current_inode = if let Ok(file) = File::open(&path) { 167 | bincode::deserialize_from(file).unwrap() 168 | } else { 169 | fuser::FUSE_ROOT_ID 170 | }; 171 | 172 | let file = OpenOptions::new() 173 | .write(true) 174 | .create(true) 175 | .truncate(true) 176 | .open(&path) 177 | .unwrap(); 178 | bincode::serialize_into(file, &(current_inode + 1)).unwrap(); 179 | 180 | current_inode + 1 181 | } 182 | 183 | fn get_inode(&self, inode: Inode) -> Result { 184 | let path = Path::new(&self.data_dir) 185 | .join("inodes") 186 | .join(inode.to_string()); 187 | if let Ok(file) = File::open(&path) { 188 | Ok(bincode::deserialize_from(file).unwrap()) 189 | } else { 190 | Err(libc::ENOENT) 191 | } 192 | } 193 | 194 | fn write_inode(&self, inode: &InodeAttributes) { 195 | let path = Path::new(&self.data_dir) 196 | .join("inodes") 197 | .join(inode.inode.to_string()); 198 | let file = OpenOptions::new() 199 | .write(true) 200 | .create(true) 201 | .truncate(true) 202 | .open(&path) 203 | .unwrap(); 204 | bincode::serialize_into(file, inode).unwrap(); 205 | } 206 | 207 | fn get_directory_content(&self, inode: Inode) -> Result { 208 | let path = Path::new(&self.data_dir) 209 | .join("contents") 210 | .join(inode.to_string()); 211 | if let Ok(file) = File::open(&path) { 212 | Ok(bincode::deserialize_from(file).unwrap()) 213 | } else { 214 | Err(libc::ENOENT) 215 | } 216 | } 217 | 218 | fn write_directory_content(&self, inode: Inode, entries: DirectoryDescriptor) { 219 | let path = Path::new(&self.data_dir) 220 | .join("contents") 221 | .join(inode.to_string()); 222 | let file = OpenOptions::new() 223 | .write(true) 224 | .create(true) 225 | .truncate(true) 226 | .open(&path) 227 | .unwrap(); 228 | bincode::serialize_into(file, &entries).unwrap(); 229 | } 230 | 231 | fn lookup_name(&self, parent: u64, name: &OsStr) -> Result { 232 | let entries = self.get_directory_content(parent)?; 233 | if let Some((inode, _)) = entries.get(name.as_bytes()) { 234 | // TODO: check metadata of the file, if not consistent, update, otherwise, return 235 | return self.get_inode(*inode); 236 | } else { 237 | // let exists = Runtime::new().unwrap().block_on(self.worker.is_exist(name.to_str().unwrap())).unwrap(); 238 | // if exists { 239 | // let inode = self.allocate_next_inode(); 240 | // let metadata = Runtime::new().unwrap().block_on(self.worker.get_stats(name.to_str().unwrap())).unwrap(); 241 | // let parent_attrs = self.get_inode(parent).unwrap(); 242 | // let mut attrs = InodeAttributes { 243 | // inode, 244 | // open_file_handles: 1, 245 | // size: 0, 246 | // last_accessed: time_now(), 247 | // last_modified: time_from_offsetdatatime(metadata.last_modified()), 248 | // last_metadata_changed: time_now(), 249 | // kind: FileKind::File, 250 | // mode: 0o777, 251 | // hardlinks: 1, 252 | // uid: parent_attrs.uid, 253 | // gid: parent_attrs.gid, 254 | // // use dummy metadata here 255 | // // md5: metadata.content_md5().unwrap().to_string(), 256 | // md5: "".to_string(), 257 | // }; 258 | // let path = self.content_path(inode); 259 | // File::create(&path).unwrap(); 260 | // let data = Runtime::new().unwrap().block_on(self.worker.get_data(name.to_str().unwrap())).unwrap(); 261 | // if let Ok(mut file) = OpenOptions::new().write(true).open(&path) { 262 | // file.seek(SeekFrom::Start(0 as u64)).unwrap(); 263 | // file.write_all(&data).unwrap(); 264 | 265 | // attrs.last_metadata_changed = time_now(); 266 | // attrs.last_modified = time_now(); 267 | // if data.len() as usize > attrs.size as usize { 268 | // attrs.size = (data.len() as usize) as u64; 269 | // } 270 | // clear_suid_sgid(&mut attrs); 271 | // self.write_inode(&attrs); 272 | 273 | // let mut entries = self.get_directory_content(parent).unwrap(); 274 | // entries.insert(name.as_bytes().to_vec(), (inode, attrs.kind)); 275 | // self.write_directory_content(parent, entries); 276 | // } 277 | 278 | 279 | // return self.get_inode(inode); 280 | // } else { 281 | // return Err(libc::ENOENT); 282 | // } 283 | return Err(libc::ENOENT); 284 | } 285 | } 286 | 287 | fn check_file_handle_read(&self, file_handle: u64) -> bool { 288 | (file_handle & FILE_HANDLE_READ_BIT) != 0 289 | } 290 | 291 | fn check_file_handle_write(&self, file_handle: u64) -> bool { 292 | (file_handle & FILE_HANDLE_WRITE_BIT) != 0 293 | } 294 | 295 | fn content_path(&self, inode: Inode) -> PathBuf { 296 | Path::new(&self.data_dir) 297 | .join("contents") 298 | .join(inode.to_string()) 299 | } 300 | 301 | // TODO: The function is only a toy at the moment that it does not support finding files in directories other than root. If want to find any file path with the inode, one might need to find a way to get its parent dir's inode for any path. 302 | fn get_filename_from_inode(&self, inode: Inode) -> String { 303 | let entries = self.get_directory_content(FUSE_ROOT_ID).unwrap(); 304 | let filename = get_key_by_value(&entries, &(inode, FileKind::File)).unwrap(); 305 | let s = String::from_utf8_lossy(filename); 306 | s.to_string() 307 | } 308 | 309 | fn creation_mode(&self, mode: u32) -> u16 { 310 | (mode & !(libc::S_ISUID | libc::S_ISGID) as u32) as u16 311 | } 312 | 313 | #[async_recursion] 314 | async fn init_directories(&self, path: &str, parent: Inode) -> Result<(), Box>{ 315 | let entries = self.worker.list_dir(path).await?; 316 | let mut parent_attrs =self.get_inode(parent).unwrap(); 317 | for file in entries { 318 | let full_path = format!("{}{}", path, file); 319 | let is_file = self.worker.is_file(&full_path).await?; 320 | 321 | if is_file { 322 | // let metadata = self.worker.get_stats(full_path.as_str()).await?; 323 | let file_inode = self.allocate_next_inode(); 324 | let attrs = InodeAttributes { 325 | inode: file_inode, 326 | open_file_handles: 1, 327 | size: 0, 328 | last_accessed: time_now(), 329 | // last_modified: time_from_offsetdatatime(metadata.last_modified()), 330 | last_modified: time_now(), 331 | last_metadata_changed: time_now(), 332 | kind: FileKind::File, 333 | mode: 0x777, 334 | hardlinks: 1, 335 | uid: parent_attrs.uid, 336 | gid: parent_attrs.gid, 337 | md5: "".to_string() 338 | }; 339 | self.write_inode(&attrs); 340 | let mut entries = self.get_directory_content(parent).unwrap(); 341 | entries.insert(file.as_bytes().to_vec(), (file_inode, attrs.kind)); 342 | self.write_directory_content(parent, entries); 343 | 344 | parent_attrs.last_modified = time_now(); 345 | parent_attrs.last_metadata_changed = time_now(); 346 | self.write_inode(&parent_attrs); 347 | } else { 348 | let dir_path = format!("{}/", full_path); 349 | let dir_inode = self.allocate_next_inode(); 350 | let attrs = InodeAttributes { 351 | inode: dir_inode, 352 | open_file_handles: 1, 353 | size: 0, 354 | last_accessed: time_now(), 355 | last_modified: time_now(), 356 | last_metadata_changed: time_now(), 357 | kind: FileKind::Directory, 358 | mode: 0x777, 359 | hardlinks: 1, 360 | uid: parent_attrs.uid, 361 | gid: parent_attrs.gid, 362 | md5: "".to_string() 363 | }; 364 | self.write_inode(&attrs); 365 | let mut entries = BTreeMap::new(); 366 | entries.insert(b"..".to_vec(), (parent, FileKind::Directory)); 367 | entries.insert(b".".to_vec(), (dir_inode, FileKind::Directory)); 368 | self.write_directory_content(dir_inode, entries); 369 | 370 | let mut parent_entries = self.get_directory_content(parent).unwrap(); 371 | let name = list_directory(dir_path.as_str()).unwrap(); 372 | parent_entries.insert(name.as_bytes().to_vec(), (dir_inode, FileKind::Directory)); 373 | self.write_directory_content(parent, parent_entries); 374 | parent_attrs.last_modified = time_now(); 375 | parent_attrs.last_metadata_changed = time_now(); 376 | self.write_inode(&parent_attrs); 377 | self.init_directories(&dir_path, dir_inode).await?; 378 | } 379 | } 380 | Ok(()) 381 | } 382 | 383 | // Check whether a file should be removed from storage. Should be called after decrementing 384 | // the link count, or closing a file handle 385 | fn gc_inode(&self, inode: &InodeAttributes) -> bool { 386 | if inode.hardlinks == 0 && inode.open_file_handles == 0 { 387 | let inode_path = Path::new(&self.data_dir) 388 | .join("inodes") 389 | .join(inode.inode.to_string()); 390 | fs::remove_file(inode_path).unwrap(); 391 | let content_path = Path::new(&self.data_dir) 392 | .join("contents") 393 | .join(inode.inode.to_string()); 394 | fs::remove_file(content_path).unwrap(); 395 | 396 | return true; 397 | } 398 | 399 | return false; 400 | } 401 | 402 | } 403 | 404 | 405 | impl Filesystem for S3FS { 406 | // Initialize filesystem. Called before any other filesystem method. 407 | // The kernel module connection can be configured using the KernelConfig object. 408 | fn init( 409 | &mut self, 410 | _req: &Request, 411 | #[allow(unused_variables)] config: &mut KernelConfig, 412 | ) -> Result<(), c_int> { 413 | fs::create_dir_all(Path::new(&self.data_dir).join("inodes")).unwrap(); 414 | fs::create_dir_all(Path::new(&self.data_dir).join("contents")).unwrap(); 415 | if self.get_inode(FUSE_ROOT_ID).is_err() { 416 | // Initialize with empty filesystem 417 | let root = InodeAttributes { 418 | inode: FUSE_ROOT_ID, 419 | open_file_handles: 0, 420 | size: 0, 421 | last_accessed: time_now(), 422 | last_modified: time_now(), 423 | last_metadata_changed: time_now(), 424 | kind: FileKind::Directory, 425 | mode: 0o777, 426 | hardlinks: 2, 427 | uid: 0, 428 | gid: 0, 429 | md5: "".to_string(), 430 | }; 431 | self.write_inode(&root); 432 | let mut entries = BTreeMap::new(); 433 | entries.insert(b".".to_vec(), (FUSE_ROOT_ID, FileKind::Directory)); 434 | self.write_directory_content(FUSE_ROOT_ID, entries); 435 | let rt = Runtime::new().unwrap(); 436 | rt.block_on(self.init_directories("", FUSE_ROOT_ID)).unwrap(); 437 | 438 | } 439 | Ok(()) 440 | } 441 | 442 | // Look up a directory entry by name and get its attributes. 443 | fn lookup(&mut self, req: &Request, parent: u64, name: &OsStr, reply: ReplyEntry) { 444 | if name.len() > MAX_NAME_LENGTH as usize { 445 | reply.error(libc::ENAMETOOLONG); 446 | return; 447 | } 448 | let parent_attrs = self.get_inode(parent).unwrap(); 449 | if !check_access( 450 | parent_attrs.uid, 451 | parent_attrs.gid, 452 | parent_attrs.mode, 453 | req.uid(), 454 | req.gid(), 455 | libc::X_OK, 456 | ) { 457 | reply.error(libc::EACCES); 458 | return; 459 | } 460 | 461 | match self.lookup_name(parent, name) { 462 | Ok(attrs) => reply.entry(&Duration::new(0, 0), &attrs.into(), 0), 463 | Err(error_code) => reply.error(error_code), 464 | } 465 | } 466 | 467 | // Get file attributes. 468 | fn getattr(&mut self, _req: &Request, inode: u64, reply: ReplyAttr) { 469 | match self.get_inode(inode) { 470 | Ok(attrs) => reply.attr(&Duration::new(0, 0), &attrs.into()), 471 | Err(error_code) => reply.error(error_code), 472 | } 473 | } 474 | 475 | // Open a file. Open flags (with the exception of O_CREAT, O_EXCL, O_NOCTTY and O_TRUNC) are available in flags. 476 | // Filesystem may store an arbitrary file handle (pointer, index, etc) in fh, and use this in other all other file operations (read, write, flush, release, fsync). 477 | fn open(&mut self, req: &Request, inode: u64, flags: i32, reply: ReplyOpen) { 478 | debug!("open() called for {:?}", inode); 479 | let (access_mask, read, write) = match flags & libc::O_ACCMODE { 480 | libc::O_RDONLY => { 481 | // Behavior is undefined, but most filesystems return EACCES 482 | if flags & libc::O_TRUNC != 0 { 483 | reply.error(libc::EACCES); 484 | return; 485 | } 486 | if flags & FMODE_EXEC != 0 { 487 | // Open is from internal exec syscall 488 | (libc::X_OK, true, false) 489 | } else { 490 | (libc::R_OK, true, false) 491 | } 492 | } 493 | libc::O_WRONLY => (libc::W_OK, false, true), 494 | libc::O_RDWR => (libc::R_OK | libc::W_OK, true, true), 495 | // Exactly one access mode flag must be specified 496 | _ => { 497 | reply.error(libc::EINVAL); 498 | return; 499 | } 500 | }; 501 | 502 | match self.get_inode(inode) { 503 | Ok(mut attr) => { 504 | // check whether the file is newest version, if not, write the newest version to local cache. initial md5 is set to empty string, so when open the file for the first time, it will load the file from the cloud. 505 | // let rt = Runtime::new().unwrap(); 506 | let rt = tokio::runtime::Builder::new_multi_thread() 507 | .worker_threads(4) // Specify the number of worker threads 508 | .enable_all() 509 | .build() 510 | .unwrap(); 511 | let filename = self.get_filename_from_inode(inode); 512 | let metadata = rt.block_on(self.worker.get_stats(&filename)).unwrap(); 513 | // if metadata.content_md5().unwrap().to_string() != attr.md5 { 514 | if time_from_offsetdatatime(metadata.last_modified()) != attr.last_modified { 515 | let path = self.content_path(inode); 516 | match rt.block_on(self.worker.get_data(filename.as_str(), path.to_str().unwrap())) { 517 | Ok(total_bytes_read) => { 518 | println!("Downloaded {} bytes", total_bytes_read); 519 | attr.md5 = metadata.content_md5().unwrap().to_string(); 520 | attr.last_metadata_changed = time_now(); 521 | attr.last_modified = time_from_offsetdatatime(metadata.last_modified()); 522 | attr.size = total_bytes_read; 523 | clear_suid_sgid(&mut attr); 524 | self.write_inode(&attr); 525 | } 526 | Err(e) => println!("Error: {}", e), 527 | } 528 | } 529 | if check_access( 530 | attr.uid, 531 | attr.gid, 532 | attr.mode, 533 | req.uid(), 534 | req.gid(), 535 | access_mask, 536 | ) { 537 | attr.open_file_handles += 1; 538 | self.write_inode(&attr); 539 | let open_flags = if self.direct_io { FOPEN_DIRECT_IO } else { 0 }; 540 | reply.opened(self.allocate_next_file_handle(read, write), open_flags); 541 | } else { 542 | reply.error(libc::EACCES); 543 | } 544 | return; 545 | } 546 | Err(error_code) => reply.error(error_code), 547 | } 548 | } 549 | 550 | // Read data. Read should send exactly the number of bytes requested except on EOF or error, otherwise the rest of the data will be substituted with zeroes. 551 | // An exception to this is when the file has been opened in ‘direct_io’ mode, in which case the return value of the read system call will reflect the return value of this operation. 552 | // fh will contain the value set by the open method, or will be undefined if the open method didn’t set any value. 553 | // flags: these are the file flags, such as O_SYNC. 554 | fn read( 555 | &mut self, 556 | _req: &Request, 557 | inode: u64, 558 | fh: u64, 559 | offset: i64, 560 | size: u32, 561 | _flags: i32, 562 | _lock_owner: Option, 563 | reply: ReplyData, 564 | ) { 565 | debug!( 566 | "read() called on {:?} offset={:?} size={:?}", 567 | inode, offset, size 568 | ); 569 | assert!(offset >= 0); 570 | if !self.check_file_handle_read(fh) { 571 | reply.error(libc::EACCES); 572 | return; 573 | } 574 | 575 | let path = self.content_path(inode); 576 | if let Ok(file) = File::open(&path) { 577 | let file_size = file.metadata().unwrap().len(); 578 | // Could underflow if file length is less than local_start 579 | let read_size = min(size, file_size.saturating_sub(offset as u64) as u32); 580 | 581 | let mut buffer = vec![0; read_size as usize]; 582 | file.read_exact_at(&mut buffer, offset as u64).unwrap(); 583 | reply.data(&buffer); 584 | } else { 585 | reply.error(libc::ENOENT); 586 | } 587 | } 588 | 589 | fn write( 590 | &mut self, 591 | _req: &Request, 592 | inode: u64, 593 | fh: u64, 594 | offset: i64, 595 | data: &[u8], 596 | _write_flags: u32, 597 | #[allow(unused_variables)] flags: i32, 598 | _lock_owner: Option, 599 | reply: ReplyWrite, 600 | ) { 601 | debug!("write() called with {:?} size={:?}", inode, data.len()); 602 | assert!(offset >= 0); 603 | if !self.check_file_handle_write(fh) { 604 | reply.error(libc::EACCES); 605 | return; 606 | } 607 | 608 | let path = self.content_path(inode); 609 | if let Ok(mut file) = OpenOptions::new().write(true).open(&path) { 610 | file.seek(SeekFrom::Start(offset as u64)).unwrap(); 611 | file.write_all(data).unwrap(); 612 | 613 | let mut attrs = self.get_inode(inode).unwrap(); 614 | attrs.last_metadata_changed = time_now(); 615 | attrs.last_modified = time_now(); 616 | if data.len() + offset as usize > attrs.size as usize { 617 | attrs.size = (data.len() + offset as usize) as u64; 618 | } 619 | clear_suid_sgid(&mut attrs); 620 | self.write_inode(&attrs); 621 | 622 | reply.written(data.len() as u32); 623 | } else { 624 | reply.error(libc::EBADF); 625 | } 626 | } 627 | 628 | fn create( 629 | &mut self, 630 | req: &Request, 631 | parent: u64, 632 | name: &OsStr, 633 | mut mode: u32, 634 | _umask: u32, 635 | flags: i32, 636 | reply: ReplyCreate, 637 | ) { 638 | debug!("create() called with {:?} {:?}", parent, name); 639 | if self.lookup_name(parent, name).is_ok() { 640 | reply.error(libc::EEXIST); 641 | return; 642 | } 643 | 644 | let (read, write) = match flags & libc::O_ACCMODE { 645 | libc::O_RDONLY => (true, false), 646 | libc::O_WRONLY => (false, true), 647 | libc::O_RDWR => (true, true), 648 | // Exactly one access mode flag must be specified 649 | _ => { 650 | reply.error(libc::EINVAL); 651 | return; 652 | } 653 | }; 654 | 655 | let mut parent_attrs = match self.get_inode(parent) { 656 | Ok(attrs) => attrs, 657 | Err(error_code) => { 658 | reply.error(error_code); 659 | return; 660 | } 661 | }; 662 | 663 | if !check_access( 664 | parent_attrs.uid, 665 | parent_attrs.gid, 666 | parent_attrs.mode, 667 | req.uid(), 668 | req.gid(), 669 | libc::W_OK, 670 | ) { 671 | reply.error(libc::EACCES); 672 | return; 673 | } 674 | parent_attrs.last_modified = time_now(); 675 | parent_attrs.last_metadata_changed = time_now(); 676 | self.write_inode(&parent_attrs); 677 | 678 | if req.uid() != 0 { 679 | mode &= !(libc::S_ISUID | libc::S_ISGID) as u32; 680 | } 681 | 682 | let inode = self.allocate_next_inode(); 683 | let attrs = InodeAttributes { 684 | inode, 685 | open_file_handles: 1, 686 | size: 0, 687 | last_accessed: time_now(), 688 | last_modified: time_now(), 689 | last_metadata_changed: time_now(), 690 | kind: as_file_kind(mode), 691 | mode: self.creation_mode(mode), 692 | hardlinks: 1, 693 | uid: req.uid(), 694 | gid: creation_gid(&parent_attrs, req.gid()), 695 | // a dummy md5, will update after writting content to it 696 | md5: "".to_string() 697 | }; 698 | self.write_inode(&attrs); 699 | File::create(self.content_path(inode)).unwrap(); 700 | 701 | if as_file_kind(mode) == FileKind::Directory { 702 | let mut entries = BTreeMap::new(); 703 | entries.insert(b".".to_vec(), (inode, FileKind::Directory)); 704 | entries.insert(b"..".to_vec(), (parent, FileKind::Directory)); 705 | self.write_directory_content(inode, entries); 706 | } 707 | 708 | let mut entries = self.get_directory_content(parent).unwrap(); 709 | entries.insert(name.as_bytes().to_vec(), (inode, attrs.kind)); 710 | self.write_directory_content(parent, entries); 711 | 712 | reply.created( 713 | &Duration::new(0, 0), 714 | &attrs.into(), 715 | 0, 716 | self.allocate_next_file_handle(read, write), 717 | 0, 718 | ); 719 | } 720 | 721 | 722 | // Open a directory. Filesystem may store an arbitrary file handle (pointer, index, etc) in fh, and use this in other all other directory stream operations (readdir, releasedir, fsyncdir). 723 | fn opendir(&mut self, req: &Request, inode: u64, flags: i32, reply: ReplyOpen) { 724 | debug!("opendir() called on {:?}", inode); 725 | let (access_mask, read, write) = match flags & libc::O_ACCMODE { 726 | libc::O_RDONLY => { 727 | // Behavior is undefined, but most filesystems return EACCES 728 | if flags & libc::O_TRUNC != 0 { 729 | reply.error(libc::EACCES); 730 | return; 731 | } 732 | (libc::R_OK, true, false) 733 | } 734 | libc::O_WRONLY => (libc::W_OK, false, true), 735 | libc::O_RDWR => (libc::R_OK | libc::W_OK, true, true), 736 | // Exactly one access mode flag must be specified 737 | _ => { 738 | reply.error(libc::EINVAL); 739 | return; 740 | } 741 | }; 742 | 743 | match self.get_inode(inode) { 744 | Ok(mut attr) => { 745 | if check_access( 746 | attr.uid, 747 | attr.gid, 748 | attr.mode, 749 | req.uid(), 750 | req.gid(), 751 | access_mask, 752 | ) { 753 | attr.open_file_handles += 1; 754 | self.write_inode(&attr); 755 | let open_flags = if self.direct_io { FOPEN_DIRECT_IO } else { 0 }; 756 | reply.opened(self.allocate_next_file_handle(read, write), open_flags); 757 | } else { 758 | reply.error(libc::EACCES); 759 | } 760 | return; 761 | } 762 | Err(error_code) => reply.error(error_code), 763 | } 764 | } 765 | 766 | // Read directory. Send a buffer filled using buffer.fill(), with size not exceeding the requested size. 767 | // Send an empty buffer on end of stream. fh will contain the value set by the opendir method, or will be undefined if the opendir method didn’t set any value. 768 | fn readdir( 769 | &mut self, 770 | _req: &Request, 771 | inode: u64, 772 | _fh: u64, 773 | offset: i64, 774 | mut reply: ReplyDirectory, 775 | ) { 776 | debug!("readdir() called with {:?}", inode); 777 | assert!(offset >= 0); 778 | let entries = match self.get_directory_content(inode) { 779 | Ok(entries) => entries, 780 | Err(error_code) => { 781 | reply.error(error_code); 782 | return; 783 | } 784 | }; 785 | 786 | for (index, entry) in entries.iter().skip(offset as usize).enumerate() { 787 | let (name, (inode, file_type)) = entry; 788 | 789 | let buffer_full: bool = reply.add( 790 | *inode, 791 | offset + index as i64 + 1, 792 | (*file_type).into(), 793 | OsStr::from_bytes(name), 794 | ); 795 | 796 | if buffer_full { 797 | break; 798 | } 799 | } 800 | 801 | reply.ok(); 802 | } 803 | 804 | 805 | fn unlink(&mut self, req: &Request, parent: u64, name: &OsStr, reply: ReplyEmpty) { 806 | debug!("unlink() called with {:?} {:?}", parent, name); 807 | let mut attrs = match self.lookup_name(parent, name) { 808 | Ok(attrs) => attrs, 809 | Err(error_code) => { 810 | reply.error(error_code); 811 | return; 812 | } 813 | }; 814 | 815 | let mut parent_attrs = match self.get_inode(parent) { 816 | Ok(attrs) => attrs, 817 | Err(error_code) => { 818 | reply.error(error_code); 819 | return; 820 | } 821 | }; 822 | 823 | if !check_access( 824 | parent_attrs.uid, 825 | parent_attrs.gid, 826 | parent_attrs.mode, 827 | req.uid(), 828 | req.gid(), 829 | libc::W_OK, 830 | ) { 831 | reply.error(libc::EACCES); 832 | return; 833 | } 834 | 835 | let uid = req.uid(); 836 | // "Sticky bit" handling 837 | if parent_attrs.mode & libc::S_ISVTX as u16 != 0 838 | && uid != 0 839 | && uid != parent_attrs.uid 840 | && uid != attrs.uid 841 | { 842 | reply.error(libc::EACCES); 843 | return; 844 | } 845 | 846 | parent_attrs.last_metadata_changed = time_now(); 847 | parent_attrs.last_modified = time_now(); 848 | self.write_inode(&parent_attrs); 849 | 850 | attrs.hardlinks -= 1; 851 | attrs.last_metadata_changed = time_now(); 852 | self.write_inode(&attrs); 853 | self.gc_inode(&attrs); 854 | 855 | let mut entries = self.get_directory_content(parent).unwrap(); 856 | entries.remove(name.as_bytes()); 857 | self.write_directory_content(parent, entries); 858 | 859 | reply.ok(); 860 | } 861 | 862 | 863 | 864 | } 865 | 866 | fn clear_suid_sgid(attr: &mut InodeAttributes) { 867 | attr.mode &= !libc::S_ISUID as u16; 868 | // SGID is only suppose to be cleared if XGRP is set 869 | if attr.mode & libc::S_IXGRP as u16 != 0 { 870 | attr.mode &= !libc::S_ISGID as u16; 871 | } 872 | } 873 | 874 | pub fn check_access( 875 | file_uid: u32, 876 | file_gid: u32, 877 | file_mode: u16, 878 | uid: u32, 879 | gid: u32, 880 | mut access_mask: i32, 881 | ) -> bool { 882 | // F_OK tests for existence of file 883 | if access_mask == libc::F_OK { 884 | return true; 885 | } 886 | let file_mode = i32::from(file_mode); 887 | 888 | // root is allowed to read & write anything 889 | if uid == 0 { 890 | // root only allowed to exec if one of the X bits is set 891 | access_mask &= libc::X_OK; 892 | access_mask -= access_mask & (file_mode >> 6); 893 | access_mask -= access_mask & (file_mode >> 3); 894 | access_mask -= access_mask & file_mode; 895 | return access_mask == 0; 896 | } 897 | 898 | if uid == file_uid { 899 | access_mask -= access_mask & (file_mode >> 6); 900 | } else if gid == file_gid { 901 | access_mask -= access_mask & (file_mode >> 3); 902 | } else { 903 | access_mask -= access_mask & file_mode; 904 | } 905 | 906 | return access_mask == 0; 907 | } 908 | 909 | 910 | fn as_file_kind(mut mode: u32) -> FileKind { 911 | mode &= libc::S_IFMT as u32; 912 | 913 | if mode == libc::S_IFREG as u32 { 914 | return FileKind::File; 915 | } else if mode == libc::S_IFDIR as u32 { 916 | return FileKind::Directory; 917 | } else { 918 | unimplemented!("{}", mode); 919 | } 920 | } 921 | 922 | fn creation_gid(parent: &InodeAttributes, gid: u32) -> u32 { 923 | if parent.mode & libc::S_ISGID as u16 != 0 { 924 | return parent.gid; 925 | } 926 | 927 | gid 928 | } 929 | 930 | fn time_from_offsetdatatime(dt: Option) -> (i64, u32) { 931 | dt.map(|dt| { 932 | let timestamp_secs = dt.unix_timestamp(); 933 | let timestamp_millis = dt.millisecond(); 934 | (timestamp_secs, timestamp_millis as u32) 935 | }).unwrap() 936 | } 937 | 938 | fn list_directory(path: &str) -> Option<&str> { 939 | let mut directories = path.split('/').filter(|s| !s.is_empty()); 940 | let last_directory = directories.next_back(); 941 | last_directory 942 | } 943 | 944 | fn get_key_by_value<'a, K, V>(map: &'a BTreeMap, value: &V) -> Option<&'a K> 945 | where 946 | K: Ord, 947 | V: PartialEq, 948 | { 949 | map.iter().find(|(_, v)| v == &value).map(|(k, _)| k) 950 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.7.6" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 10 | dependencies = [ 11 | "getrandom", 12 | "once_cell", 13 | "version_check", 14 | ] 15 | 16 | [[package]] 17 | name = "aho-corasick" 18 | version = "0.7.20" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" 21 | dependencies = [ 22 | "memchr", 23 | ] 24 | 25 | [[package]] 26 | name = "anyhow" 27 | version = "1.0.70" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" 30 | 31 | [[package]] 32 | name = "async-compat" 33 | version = "0.2.1" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "9b48b4ff0c2026db683dea961cd8ea874737f56cffca86fa84415eaddc51c00d" 36 | dependencies = [ 37 | "futures-core", 38 | "futures-io", 39 | "once_cell", 40 | "pin-project-lite", 41 | "tokio", 42 | ] 43 | 44 | [[package]] 45 | name = "async-recursion" 46 | version = "1.0.4" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" 49 | dependencies = [ 50 | "proc-macro2", 51 | "quote", 52 | "syn 2.0.10", 53 | ] 54 | 55 | [[package]] 56 | name = "async-trait" 57 | version = "0.1.68" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" 60 | dependencies = [ 61 | "proc-macro2", 62 | "quote", 63 | "syn 2.0.10", 64 | ] 65 | 66 | [[package]] 67 | name = "atty" 68 | version = "0.2.14" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 71 | dependencies = [ 72 | "hermit-abi 0.1.19", 73 | "libc", 74 | "winapi", 75 | ] 76 | 77 | [[package]] 78 | name = "autocfg" 79 | version = "1.1.0" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 82 | 83 | [[package]] 84 | name = "backon" 85 | version = "0.4.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "f34fac4d7cdaefa2deded0eda2d5d59dbfd43370ff3f856209e72340ae84c294" 88 | dependencies = [ 89 | "futures", 90 | "pin-project", 91 | "rand", 92 | "tokio", 93 | ] 94 | 95 | [[package]] 96 | name = "base64" 97 | version = "0.13.1" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 100 | 101 | [[package]] 102 | name = "base64" 103 | version = "0.21.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" 106 | 107 | [[package]] 108 | name = "base64ct" 109 | version = "1.6.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 112 | 113 | [[package]] 114 | name = "bincode" 115 | version = "1.3.3" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 118 | dependencies = [ 119 | "serde", 120 | ] 121 | 122 | [[package]] 123 | name = "bitflags" 124 | version = "1.3.2" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 127 | 128 | [[package]] 129 | name = "block-buffer" 130 | version = "0.10.4" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 133 | dependencies = [ 134 | "generic-array", 135 | ] 136 | 137 | [[package]] 138 | name = "bumpalo" 139 | version = "3.12.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" 142 | 143 | [[package]] 144 | name = "byteorder" 145 | version = "1.4.3" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 148 | 149 | [[package]] 150 | name = "bytes" 151 | version = "1.4.0" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" 154 | 155 | [[package]] 156 | name = "cc" 157 | version = "1.0.79" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" 160 | 161 | [[package]] 162 | name = "cfg-if" 163 | version = "1.0.0" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 166 | 167 | [[package]] 168 | name = "clap" 169 | version = "3.2.23" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" 172 | dependencies = [ 173 | "atty", 174 | "bitflags", 175 | "clap_derive", 176 | "clap_lex", 177 | "indexmap", 178 | "once_cell", 179 | "strsim", 180 | "termcolor", 181 | "textwrap", 182 | ] 183 | 184 | [[package]] 185 | name = "clap_derive" 186 | version = "3.2.18" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" 189 | dependencies = [ 190 | "heck", 191 | "proc-macro-error", 192 | "proc-macro2", 193 | "quote", 194 | "syn 1.0.109", 195 | ] 196 | 197 | [[package]] 198 | name = "clap_lex" 199 | version = "0.2.4" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" 202 | dependencies = [ 203 | "os_str_bytes", 204 | ] 205 | 206 | [[package]] 207 | name = "const-oid" 208 | version = "0.9.2" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" 211 | 212 | [[package]] 213 | name = "core-foundation" 214 | version = "0.9.3" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" 217 | dependencies = [ 218 | "core-foundation-sys", 219 | "libc", 220 | ] 221 | 222 | [[package]] 223 | name = "core-foundation-sys" 224 | version = "0.8.3" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 227 | 228 | [[package]] 229 | name = "cpufeatures" 230 | version = "0.2.6" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" 233 | dependencies = [ 234 | "libc", 235 | ] 236 | 237 | [[package]] 238 | name = "crossbeam-channel" 239 | version = "0.5.8" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" 242 | dependencies = [ 243 | "cfg-if", 244 | "crossbeam-utils", 245 | ] 246 | 247 | [[package]] 248 | name = "crossbeam-deque" 249 | version = "0.8.3" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" 252 | dependencies = [ 253 | "cfg-if", 254 | "crossbeam-epoch", 255 | "crossbeam-utils", 256 | ] 257 | 258 | [[package]] 259 | name = "crossbeam-epoch" 260 | version = "0.9.14" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" 263 | dependencies = [ 264 | "autocfg", 265 | "cfg-if", 266 | "crossbeam-utils", 267 | "memoffset", 268 | "scopeguard", 269 | ] 270 | 271 | [[package]] 272 | name = "crossbeam-utils" 273 | version = "0.8.15" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" 276 | dependencies = [ 277 | "cfg-if", 278 | ] 279 | 280 | [[package]] 281 | name = "crypto-common" 282 | version = "0.1.6" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 285 | dependencies = [ 286 | "generic-array", 287 | "typenum", 288 | ] 289 | 290 | [[package]] 291 | name = "der" 292 | version = "0.6.1" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" 295 | dependencies = [ 296 | "const-oid", 297 | "pem-rfc7468", 298 | "zeroize", 299 | ] 300 | 301 | [[package]] 302 | name = "digest" 303 | version = "0.10.6" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" 306 | dependencies = [ 307 | "block-buffer", 308 | "const-oid", 309 | "crypto-common", 310 | "subtle", 311 | ] 312 | 313 | [[package]] 314 | name = "dirs" 315 | version = "4.0.0" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" 318 | dependencies = [ 319 | "dirs-sys", 320 | ] 321 | 322 | [[package]] 323 | name = "dirs-sys" 324 | version = "0.3.7" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 327 | dependencies = [ 328 | "libc", 329 | "redox_users", 330 | "winapi", 331 | ] 332 | 333 | [[package]] 334 | name = "dlv-list" 335 | version = "0.3.0" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" 338 | 339 | [[package]] 340 | name = "either" 341 | version = "1.8.1" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" 344 | 345 | [[package]] 346 | name = "encoding_rs" 347 | version = "0.8.32" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" 350 | dependencies = [ 351 | "cfg-if", 352 | ] 353 | 354 | [[package]] 355 | name = "env_logger" 356 | version = "0.9.3" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" 359 | dependencies = [ 360 | "atty", 361 | "humantime", 362 | "log", 363 | "regex", 364 | "termcolor", 365 | ] 366 | 367 | [[package]] 368 | name = "flagset" 369 | version = "0.4.3" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499" 372 | 373 | [[package]] 374 | name = "fnv" 375 | version = "1.0.7" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 378 | 379 | [[package]] 380 | name = "form_urlencoded" 381 | version = "1.1.0" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" 384 | dependencies = [ 385 | "percent-encoding", 386 | ] 387 | 388 | [[package]] 389 | name = "fuser" 390 | version = "0.12.0" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "5910691a0ececcc6eba8bb14029025c2d123e96a53db1533f6a4602861a5aaf7" 393 | dependencies = [ 394 | "libc", 395 | "log", 396 | "memchr", 397 | "page_size", 398 | "pkg-config", 399 | "smallvec", 400 | "users", 401 | "zerocopy", 402 | ] 403 | 404 | [[package]] 405 | name = "futures" 406 | version = "0.3.28" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" 409 | dependencies = [ 410 | "futures-channel", 411 | "futures-core", 412 | "futures-executor", 413 | "futures-io", 414 | "futures-sink", 415 | "futures-task", 416 | "futures-util", 417 | ] 418 | 419 | [[package]] 420 | name = "futures-channel" 421 | version = "0.3.28" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" 424 | dependencies = [ 425 | "futures-core", 426 | "futures-sink", 427 | ] 428 | 429 | [[package]] 430 | name = "futures-core" 431 | version = "0.3.28" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" 434 | 435 | [[package]] 436 | name = "futures-executor" 437 | version = "0.3.28" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" 440 | dependencies = [ 441 | "futures-core", 442 | "futures-task", 443 | "futures-util", 444 | ] 445 | 446 | [[package]] 447 | name = "futures-io" 448 | version = "0.3.28" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" 451 | 452 | [[package]] 453 | name = "futures-macro" 454 | version = "0.3.28" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" 457 | dependencies = [ 458 | "proc-macro2", 459 | "quote", 460 | "syn 2.0.10", 461 | ] 462 | 463 | [[package]] 464 | name = "futures-sink" 465 | version = "0.3.28" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" 468 | 469 | [[package]] 470 | name = "futures-task" 471 | version = "0.3.28" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" 474 | 475 | [[package]] 476 | name = "futures-util" 477 | version = "0.3.28" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" 480 | dependencies = [ 481 | "futures-channel", 482 | "futures-core", 483 | "futures-io", 484 | "futures-macro", 485 | "futures-sink", 486 | "futures-task", 487 | "memchr", 488 | "pin-project-lite", 489 | "pin-utils", 490 | "slab", 491 | ] 492 | 493 | [[package]] 494 | name = "generic-array" 495 | version = "0.14.7" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 498 | dependencies = [ 499 | "typenum", 500 | "version_check", 501 | ] 502 | 503 | [[package]] 504 | name = "getrandom" 505 | version = "0.2.8" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" 508 | dependencies = [ 509 | "cfg-if", 510 | "libc", 511 | "wasi", 512 | ] 513 | 514 | [[package]] 515 | name = "h2" 516 | version = "0.3.16" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" 519 | dependencies = [ 520 | "bytes", 521 | "fnv", 522 | "futures-core", 523 | "futures-sink", 524 | "futures-util", 525 | "http", 526 | "indexmap", 527 | "slab", 528 | "tokio", 529 | "tokio-util", 530 | "tracing", 531 | ] 532 | 533 | [[package]] 534 | name = "hashbrown" 535 | version = "0.12.3" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 538 | dependencies = [ 539 | "ahash", 540 | ] 541 | 542 | [[package]] 543 | name = "heck" 544 | version = "0.4.1" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 547 | 548 | [[package]] 549 | name = "hermit-abi" 550 | version = "0.1.19" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 553 | dependencies = [ 554 | "libc", 555 | ] 556 | 557 | [[package]] 558 | name = "hermit-abi" 559 | version = "0.2.6" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" 562 | dependencies = [ 563 | "libc", 564 | ] 565 | 566 | [[package]] 567 | name = "hex" 568 | version = "0.4.3" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 571 | 572 | [[package]] 573 | name = "hmac" 574 | version = "0.12.1" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 577 | dependencies = [ 578 | "digest", 579 | ] 580 | 581 | [[package]] 582 | name = "http" 583 | version = "0.2.9" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" 586 | dependencies = [ 587 | "bytes", 588 | "fnv", 589 | "itoa", 590 | ] 591 | 592 | [[package]] 593 | name = "http-body" 594 | version = "0.4.5" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 597 | dependencies = [ 598 | "bytes", 599 | "http", 600 | "pin-project-lite", 601 | ] 602 | 603 | [[package]] 604 | name = "httparse" 605 | version = "1.8.0" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 608 | 609 | [[package]] 610 | name = "httpdate" 611 | version = "1.0.2" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 614 | 615 | [[package]] 616 | name = "humantime" 617 | version = "2.1.0" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 620 | 621 | [[package]] 622 | name = "hyper" 623 | version = "0.14.25" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" 626 | dependencies = [ 627 | "bytes", 628 | "futures-channel", 629 | "futures-core", 630 | "futures-util", 631 | "h2", 632 | "http", 633 | "http-body", 634 | "httparse", 635 | "httpdate", 636 | "itoa", 637 | "pin-project-lite", 638 | "socket2", 639 | "tokio", 640 | "tower-service", 641 | "tracing", 642 | "want", 643 | ] 644 | 645 | [[package]] 646 | name = "hyper-rustls" 647 | version = "0.23.2" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" 650 | dependencies = [ 651 | "http", 652 | "hyper", 653 | "rustls", 654 | "tokio", 655 | "tokio-rustls", 656 | ] 657 | 658 | [[package]] 659 | name = "idna" 660 | version = "0.3.0" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" 663 | dependencies = [ 664 | "unicode-bidi", 665 | "unicode-normalization", 666 | ] 667 | 668 | [[package]] 669 | name = "indexmap" 670 | version = "1.9.3" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 673 | dependencies = [ 674 | "autocfg", 675 | "hashbrown", 676 | ] 677 | 678 | [[package]] 679 | name = "ipnet" 680 | version = "2.7.2" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" 683 | 684 | [[package]] 685 | name = "itoa" 686 | version = "1.0.6" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" 689 | 690 | [[package]] 691 | name = "js-sys" 692 | version = "0.3.61" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" 695 | dependencies = [ 696 | "wasm-bindgen", 697 | ] 698 | 699 | [[package]] 700 | name = "jsonwebtoken" 701 | version = "8.3.0" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" 704 | dependencies = [ 705 | "base64 0.21.0", 706 | "pem", 707 | "ring", 708 | "serde", 709 | "serde_json", 710 | "simple_asn1", 711 | ] 712 | 713 | [[package]] 714 | name = "lazy_static" 715 | version = "1.4.0" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 718 | dependencies = [ 719 | "spin", 720 | ] 721 | 722 | [[package]] 723 | name = "libc" 724 | version = "0.2.140" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" 727 | 728 | [[package]] 729 | name = "libm" 730 | version = "0.2.6" 731 | source = "registry+https://github.com/rust-lang/crates.io-index" 732 | checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" 733 | 734 | [[package]] 735 | name = "lock_api" 736 | version = "0.4.9" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" 739 | dependencies = [ 740 | "autocfg", 741 | "scopeguard", 742 | ] 743 | 744 | [[package]] 745 | name = "log" 746 | version = "0.4.17" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 749 | dependencies = [ 750 | "cfg-if", 751 | ] 752 | 753 | [[package]] 754 | name = "md-5" 755 | version = "0.10.5" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" 758 | dependencies = [ 759 | "digest", 760 | ] 761 | 762 | [[package]] 763 | name = "memchr" 764 | version = "2.5.0" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 767 | 768 | [[package]] 769 | name = "memoffset" 770 | version = "0.8.0" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" 773 | dependencies = [ 774 | "autocfg", 775 | ] 776 | 777 | [[package]] 778 | name = "mime" 779 | version = "0.3.17" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 782 | 783 | [[package]] 784 | name = "mime_guess" 785 | version = "2.0.4" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" 788 | dependencies = [ 789 | "mime", 790 | "unicase", 791 | ] 792 | 793 | [[package]] 794 | name = "mio" 795 | version = "0.8.6" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" 798 | dependencies = [ 799 | "libc", 800 | "log", 801 | "wasi", 802 | "windows-sys 0.45.0", 803 | ] 804 | 805 | [[package]] 806 | name = "num-bigint" 807 | version = "0.4.3" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" 810 | dependencies = [ 811 | "autocfg", 812 | "num-integer", 813 | "num-traits", 814 | ] 815 | 816 | [[package]] 817 | name = "num-bigint-dig" 818 | version = "0.8.2" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" 821 | dependencies = [ 822 | "byteorder", 823 | "lazy_static", 824 | "libm", 825 | "num-integer", 826 | "num-iter", 827 | "num-traits", 828 | "rand", 829 | "smallvec", 830 | "zeroize", 831 | ] 832 | 833 | [[package]] 834 | name = "num-integer" 835 | version = "0.1.45" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 838 | dependencies = [ 839 | "autocfg", 840 | "num-traits", 841 | ] 842 | 843 | [[package]] 844 | name = "num-iter" 845 | version = "0.1.43" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" 848 | dependencies = [ 849 | "autocfg", 850 | "num-integer", 851 | "num-traits", 852 | ] 853 | 854 | [[package]] 855 | name = "num-traits" 856 | version = "0.2.15" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 859 | dependencies = [ 860 | "autocfg", 861 | "libm", 862 | ] 863 | 864 | [[package]] 865 | name = "num_cpus" 866 | version = "1.15.0" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" 869 | dependencies = [ 870 | "hermit-abi 0.2.6", 871 | "libc", 872 | ] 873 | 874 | [[package]] 875 | name = "once_cell" 876 | version = "1.17.1" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" 879 | 880 | [[package]] 881 | name = "opendal" 882 | version = "0.30.5" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "a89d32f1761175aff31cb233330e206c2a8d9c3e96b0af3e74d0e7eff978b46a" 885 | dependencies = [ 886 | "anyhow", 887 | "async-compat", 888 | "async-trait", 889 | "backon", 890 | "base64 0.21.0", 891 | "bytes", 892 | "flagset", 893 | "futures", 894 | "http", 895 | "hyper", 896 | "log", 897 | "md-5", 898 | "once_cell", 899 | "parking_lot", 900 | "percent-encoding", 901 | "pin-project", 902 | "quick-xml 0.27.1", 903 | "reqsign", 904 | "reqwest", 905 | "serde", 906 | "serde_json", 907 | "time", 908 | "tokio", 909 | "ureq", 910 | "uuid", 911 | ] 912 | 913 | [[package]] 914 | name = "openssl-probe" 915 | version = "0.1.5" 916 | source = "registry+https://github.com/rust-lang/crates.io-index" 917 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 918 | 919 | [[package]] 920 | name = "ordered-multimap" 921 | version = "0.4.3" 922 | source = "registry+https://github.com/rust-lang/crates.io-index" 923 | checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" 924 | dependencies = [ 925 | "dlv-list", 926 | "hashbrown", 927 | ] 928 | 929 | [[package]] 930 | name = "os_str_bytes" 931 | version = "6.5.0" 932 | source = "registry+https://github.com/rust-lang/crates.io-index" 933 | checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" 934 | 935 | [[package]] 936 | name = "page_size" 937 | version = "0.4.2" 938 | source = "registry+https://github.com/rust-lang/crates.io-index" 939 | checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" 940 | dependencies = [ 941 | "libc", 942 | "winapi", 943 | ] 944 | 945 | [[package]] 946 | name = "parking_lot" 947 | version = "0.12.1" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 950 | dependencies = [ 951 | "lock_api", 952 | "parking_lot_core", 953 | ] 954 | 955 | [[package]] 956 | name = "parking_lot_core" 957 | version = "0.9.7" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" 960 | dependencies = [ 961 | "cfg-if", 962 | "libc", 963 | "redox_syscall", 964 | "smallvec", 965 | "windows-sys 0.45.0", 966 | ] 967 | 968 | [[package]] 969 | name = "pem" 970 | version = "1.1.1" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" 973 | dependencies = [ 974 | "base64 0.13.1", 975 | ] 976 | 977 | [[package]] 978 | name = "pem-rfc7468" 979 | version = "0.6.0" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" 982 | dependencies = [ 983 | "base64ct", 984 | ] 985 | 986 | [[package]] 987 | name = "percent-encoding" 988 | version = "2.2.0" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" 991 | 992 | [[package]] 993 | name = "pin-project" 994 | version = "1.0.12" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" 997 | dependencies = [ 998 | "pin-project-internal", 999 | ] 1000 | 1001 | [[package]] 1002 | name = "pin-project-internal" 1003 | version = "1.0.12" 1004 | source = "registry+https://github.com/rust-lang/crates.io-index" 1005 | checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" 1006 | dependencies = [ 1007 | "proc-macro2", 1008 | "quote", 1009 | "syn 1.0.109", 1010 | ] 1011 | 1012 | [[package]] 1013 | name = "pin-project-lite" 1014 | version = "0.2.9" 1015 | source = "registry+https://github.com/rust-lang/crates.io-index" 1016 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 1017 | 1018 | [[package]] 1019 | name = "pin-utils" 1020 | version = "0.1.0" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1023 | 1024 | [[package]] 1025 | name = "pkcs1" 1026 | version = "0.4.1" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" 1029 | dependencies = [ 1030 | "der", 1031 | "pkcs8", 1032 | "spki", 1033 | "zeroize", 1034 | ] 1035 | 1036 | [[package]] 1037 | name = "pkcs8" 1038 | version = "0.9.0" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" 1041 | dependencies = [ 1042 | "der", 1043 | "spki", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "pkg-config" 1048 | version = "0.3.26" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" 1051 | 1052 | [[package]] 1053 | name = "ppv-lite86" 1054 | version = "0.2.17" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1057 | 1058 | [[package]] 1059 | name = "proc-macro-error" 1060 | version = "1.0.4" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1063 | dependencies = [ 1064 | "proc-macro-error-attr", 1065 | "proc-macro2", 1066 | "quote", 1067 | "syn 1.0.109", 1068 | "version_check", 1069 | ] 1070 | 1071 | [[package]] 1072 | name = "proc-macro-error-attr" 1073 | version = "1.0.4" 1074 | source = "registry+https://github.com/rust-lang/crates.io-index" 1075 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1076 | dependencies = [ 1077 | "proc-macro2", 1078 | "quote", 1079 | "version_check", 1080 | ] 1081 | 1082 | [[package]] 1083 | name = "proc-macro2" 1084 | version = "1.0.53" 1085 | source = "registry+https://github.com/rust-lang/crates.io-index" 1086 | checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" 1087 | dependencies = [ 1088 | "unicode-ident", 1089 | ] 1090 | 1091 | [[package]] 1092 | name = "quick-xml" 1093 | version = "0.27.1" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "ffc053f057dd768a56f62cd7e434c42c831d296968997e9ac1f76ea7c2d14c41" 1096 | dependencies = [ 1097 | "memchr", 1098 | "serde", 1099 | ] 1100 | 1101 | [[package]] 1102 | name = "quick-xml" 1103 | version = "0.28.1" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "e5c1a97b1bc42b1d550bfb48d4262153fe400a12bab1511821736f7eac76d7e2" 1106 | dependencies = [ 1107 | "memchr", 1108 | "serde", 1109 | ] 1110 | 1111 | [[package]] 1112 | name = "quote" 1113 | version = "1.0.26" 1114 | source = "registry+https://github.com/rust-lang/crates.io-index" 1115 | checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" 1116 | dependencies = [ 1117 | "proc-macro2", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "rand" 1122 | version = "0.8.5" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1125 | dependencies = [ 1126 | "libc", 1127 | "rand_chacha", 1128 | "rand_core", 1129 | ] 1130 | 1131 | [[package]] 1132 | name = "rand_chacha" 1133 | version = "0.3.1" 1134 | source = "registry+https://github.com/rust-lang/crates.io-index" 1135 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1136 | dependencies = [ 1137 | "ppv-lite86", 1138 | "rand_core", 1139 | ] 1140 | 1141 | [[package]] 1142 | name = "rand_core" 1143 | version = "0.6.4" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1146 | dependencies = [ 1147 | "getrandom", 1148 | ] 1149 | 1150 | [[package]] 1151 | name = "rayon" 1152 | version = "1.7.0" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" 1155 | dependencies = [ 1156 | "either", 1157 | "rayon-core", 1158 | ] 1159 | 1160 | [[package]] 1161 | name = "rayon-core" 1162 | version = "1.11.0" 1163 | source = "registry+https://github.com/rust-lang/crates.io-index" 1164 | checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" 1165 | dependencies = [ 1166 | "crossbeam-channel", 1167 | "crossbeam-deque", 1168 | "crossbeam-utils", 1169 | "num_cpus", 1170 | ] 1171 | 1172 | [[package]] 1173 | name = "redox_syscall" 1174 | version = "0.2.16" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 1177 | dependencies = [ 1178 | "bitflags", 1179 | ] 1180 | 1181 | [[package]] 1182 | name = "redox_users" 1183 | version = "0.4.3" 1184 | source = "registry+https://github.com/rust-lang/crates.io-index" 1185 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 1186 | dependencies = [ 1187 | "getrandom", 1188 | "redox_syscall", 1189 | "thiserror", 1190 | ] 1191 | 1192 | [[package]] 1193 | name = "regex" 1194 | version = "1.7.3" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" 1197 | dependencies = [ 1198 | "aho-corasick", 1199 | "memchr", 1200 | "regex-syntax", 1201 | ] 1202 | 1203 | [[package]] 1204 | name = "regex-syntax" 1205 | version = "0.6.29" 1206 | source = "registry+https://github.com/rust-lang/crates.io-index" 1207 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1208 | 1209 | [[package]] 1210 | name = "reqsign" 1211 | version = "0.8.5" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "a7db6d8d2cd7fa61403d14de670f98d7cedac38143681c124943d7bb69258b3a" 1214 | dependencies = [ 1215 | "anyhow", 1216 | "backon", 1217 | "base64 0.21.0", 1218 | "bytes", 1219 | "dirs", 1220 | "form_urlencoded", 1221 | "hex", 1222 | "hmac", 1223 | "http", 1224 | "jsonwebtoken", 1225 | "log", 1226 | "once_cell", 1227 | "percent-encoding", 1228 | "quick-xml 0.28.1", 1229 | "rand", 1230 | "rsa", 1231 | "rust-ini", 1232 | "serde", 1233 | "serde_json", 1234 | "sha1", 1235 | "sha2", 1236 | "time", 1237 | "ureq", 1238 | ] 1239 | 1240 | [[package]] 1241 | name = "reqwest" 1242 | version = "0.11.16" 1243 | source = "registry+https://github.com/rust-lang/crates.io-index" 1244 | checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" 1245 | dependencies = [ 1246 | "base64 0.21.0", 1247 | "bytes", 1248 | "encoding_rs", 1249 | "futures-core", 1250 | "futures-util", 1251 | "h2", 1252 | "http", 1253 | "http-body", 1254 | "hyper", 1255 | "hyper-rustls", 1256 | "ipnet", 1257 | "js-sys", 1258 | "log", 1259 | "mime", 1260 | "mime_guess", 1261 | "once_cell", 1262 | "percent-encoding", 1263 | "pin-project-lite", 1264 | "rustls", 1265 | "rustls-native-certs", 1266 | "rustls-pemfile", 1267 | "serde", 1268 | "serde_json", 1269 | "serde_urlencoded", 1270 | "tokio", 1271 | "tokio-rustls", 1272 | "tokio-util", 1273 | "tower-service", 1274 | "url", 1275 | "wasm-bindgen", 1276 | "wasm-bindgen-futures", 1277 | "wasm-streams", 1278 | "web-sys", 1279 | "winreg", 1280 | ] 1281 | 1282 | [[package]] 1283 | name = "ring" 1284 | version = "0.16.20" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 1287 | dependencies = [ 1288 | "cc", 1289 | "libc", 1290 | "once_cell", 1291 | "spin", 1292 | "untrusted", 1293 | "web-sys", 1294 | "winapi", 1295 | ] 1296 | 1297 | [[package]] 1298 | name = "rsa" 1299 | version = "0.8.2" 1300 | source = "registry+https://github.com/rust-lang/crates.io-index" 1301 | checksum = "55a77d189da1fee555ad95b7e50e7457d91c0e089ec68ca69ad2989413bbdab4" 1302 | dependencies = [ 1303 | "byteorder", 1304 | "digest", 1305 | "num-bigint-dig", 1306 | "num-integer", 1307 | "num-iter", 1308 | "num-traits", 1309 | "pkcs1", 1310 | "pkcs8", 1311 | "rand_core", 1312 | "sha2", 1313 | "signature", 1314 | "subtle", 1315 | "zeroize", 1316 | ] 1317 | 1318 | [[package]] 1319 | name = "rust-ini" 1320 | version = "0.18.0" 1321 | source = "registry+https://github.com/rust-lang/crates.io-index" 1322 | checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" 1323 | dependencies = [ 1324 | "cfg-if", 1325 | "ordered-multimap", 1326 | ] 1327 | 1328 | [[package]] 1329 | name = "rustls" 1330 | version = "0.20.8" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" 1333 | dependencies = [ 1334 | "log", 1335 | "ring", 1336 | "sct", 1337 | "webpki", 1338 | ] 1339 | 1340 | [[package]] 1341 | name = "rustls-native-certs" 1342 | version = "0.6.2" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" 1345 | dependencies = [ 1346 | "openssl-probe", 1347 | "rustls-pemfile", 1348 | "schannel", 1349 | "security-framework", 1350 | ] 1351 | 1352 | [[package]] 1353 | name = "rustls-pemfile" 1354 | version = "1.0.2" 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" 1356 | checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" 1357 | dependencies = [ 1358 | "base64 0.21.0", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "rusty-s3fs" 1363 | version = "0.1.0" 1364 | dependencies = [ 1365 | "anyhow", 1366 | "async-recursion", 1367 | "bincode", 1368 | "clap", 1369 | "env_logger", 1370 | "fuser", 1371 | "futures", 1372 | "libc", 1373 | "log", 1374 | "opendal", 1375 | "rayon", 1376 | "serde", 1377 | "time", 1378 | "tokio", 1379 | ] 1380 | 1381 | [[package]] 1382 | name = "ryu" 1383 | version = "1.0.13" 1384 | source = "registry+https://github.com/rust-lang/crates.io-index" 1385 | checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" 1386 | 1387 | [[package]] 1388 | name = "schannel" 1389 | version = "0.1.21" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" 1392 | dependencies = [ 1393 | "windows-sys 0.42.0", 1394 | ] 1395 | 1396 | [[package]] 1397 | name = "scopeguard" 1398 | version = "1.1.0" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1401 | 1402 | [[package]] 1403 | name = "sct" 1404 | version = "0.7.0" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" 1407 | dependencies = [ 1408 | "ring", 1409 | "untrusted", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "security-framework" 1414 | version = "2.8.2" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" 1417 | dependencies = [ 1418 | "bitflags", 1419 | "core-foundation", 1420 | "core-foundation-sys", 1421 | "libc", 1422 | "security-framework-sys", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "security-framework-sys" 1427 | version = "2.8.0" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" 1430 | dependencies = [ 1431 | "core-foundation-sys", 1432 | "libc", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "serde" 1437 | version = "1.0.158" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" 1440 | dependencies = [ 1441 | "serde_derive", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "serde_derive" 1446 | version = "1.0.158" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" 1449 | dependencies = [ 1450 | "proc-macro2", 1451 | "quote", 1452 | "syn 2.0.10", 1453 | ] 1454 | 1455 | [[package]] 1456 | name = "serde_json" 1457 | version = "1.0.95" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" 1460 | dependencies = [ 1461 | "itoa", 1462 | "ryu", 1463 | "serde", 1464 | ] 1465 | 1466 | [[package]] 1467 | name = "serde_urlencoded" 1468 | version = "0.7.1" 1469 | source = "registry+https://github.com/rust-lang/crates.io-index" 1470 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1471 | dependencies = [ 1472 | "form_urlencoded", 1473 | "itoa", 1474 | "ryu", 1475 | "serde", 1476 | ] 1477 | 1478 | [[package]] 1479 | name = "sha1" 1480 | version = "0.10.5" 1481 | source = "registry+https://github.com/rust-lang/crates.io-index" 1482 | checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" 1483 | dependencies = [ 1484 | "cfg-if", 1485 | "cpufeatures", 1486 | "digest", 1487 | ] 1488 | 1489 | [[package]] 1490 | name = "sha2" 1491 | version = "0.10.6" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" 1494 | dependencies = [ 1495 | "cfg-if", 1496 | "cpufeatures", 1497 | "digest", 1498 | ] 1499 | 1500 | [[package]] 1501 | name = "signal-hook-registry" 1502 | version = "1.4.1" 1503 | source = "registry+https://github.com/rust-lang/crates.io-index" 1504 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" 1505 | dependencies = [ 1506 | "libc", 1507 | ] 1508 | 1509 | [[package]] 1510 | name = "signature" 1511 | version = "2.0.0" 1512 | source = "registry+https://github.com/rust-lang/crates.io-index" 1513 | checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" 1514 | dependencies = [ 1515 | "digest", 1516 | "rand_core", 1517 | ] 1518 | 1519 | [[package]] 1520 | name = "simple_asn1" 1521 | version = "0.6.2" 1522 | source = "registry+https://github.com/rust-lang/crates.io-index" 1523 | checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" 1524 | dependencies = [ 1525 | "num-bigint", 1526 | "num-traits", 1527 | "thiserror", 1528 | "time", 1529 | ] 1530 | 1531 | [[package]] 1532 | name = "slab" 1533 | version = "0.4.8" 1534 | source = "registry+https://github.com/rust-lang/crates.io-index" 1535 | checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" 1536 | dependencies = [ 1537 | "autocfg", 1538 | ] 1539 | 1540 | [[package]] 1541 | name = "smallvec" 1542 | version = "1.10.0" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 1545 | 1546 | [[package]] 1547 | name = "socket2" 1548 | version = "0.4.9" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" 1551 | dependencies = [ 1552 | "libc", 1553 | "winapi", 1554 | ] 1555 | 1556 | [[package]] 1557 | name = "spin" 1558 | version = "0.5.2" 1559 | source = "registry+https://github.com/rust-lang/crates.io-index" 1560 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1561 | 1562 | [[package]] 1563 | name = "spki" 1564 | version = "0.6.0" 1565 | source = "registry+https://github.com/rust-lang/crates.io-index" 1566 | checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" 1567 | dependencies = [ 1568 | "base64ct", 1569 | "der", 1570 | ] 1571 | 1572 | [[package]] 1573 | name = "strsim" 1574 | version = "0.10.0" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1577 | 1578 | [[package]] 1579 | name = "subtle" 1580 | version = "2.4.1" 1581 | source = "registry+https://github.com/rust-lang/crates.io-index" 1582 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1583 | 1584 | [[package]] 1585 | name = "syn" 1586 | version = "1.0.109" 1587 | source = "registry+https://github.com/rust-lang/crates.io-index" 1588 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1589 | dependencies = [ 1590 | "proc-macro2", 1591 | "quote", 1592 | "unicode-ident", 1593 | ] 1594 | 1595 | [[package]] 1596 | name = "syn" 1597 | version = "2.0.10" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" 1600 | dependencies = [ 1601 | "proc-macro2", 1602 | "quote", 1603 | "unicode-ident", 1604 | ] 1605 | 1606 | [[package]] 1607 | name = "termcolor" 1608 | version = "1.2.0" 1609 | source = "registry+https://github.com/rust-lang/crates.io-index" 1610 | checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" 1611 | dependencies = [ 1612 | "winapi-util", 1613 | ] 1614 | 1615 | [[package]] 1616 | name = "textwrap" 1617 | version = "0.16.0" 1618 | source = "registry+https://github.com/rust-lang/crates.io-index" 1619 | checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" 1620 | 1621 | [[package]] 1622 | name = "thiserror" 1623 | version = "1.0.40" 1624 | source = "registry+https://github.com/rust-lang/crates.io-index" 1625 | checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" 1626 | dependencies = [ 1627 | "thiserror-impl", 1628 | ] 1629 | 1630 | [[package]] 1631 | name = "thiserror-impl" 1632 | version = "1.0.40" 1633 | source = "registry+https://github.com/rust-lang/crates.io-index" 1634 | checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" 1635 | dependencies = [ 1636 | "proc-macro2", 1637 | "quote", 1638 | "syn 2.0.10", 1639 | ] 1640 | 1641 | [[package]] 1642 | name = "time" 1643 | version = "0.3.20" 1644 | source = "registry+https://github.com/rust-lang/crates.io-index" 1645 | checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" 1646 | dependencies = [ 1647 | "itoa", 1648 | "serde", 1649 | "time-core", 1650 | "time-macros", 1651 | ] 1652 | 1653 | [[package]] 1654 | name = "time-core" 1655 | version = "0.1.0" 1656 | source = "registry+https://github.com/rust-lang/crates.io-index" 1657 | checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" 1658 | 1659 | [[package]] 1660 | name = "time-macros" 1661 | version = "0.2.8" 1662 | source = "registry+https://github.com/rust-lang/crates.io-index" 1663 | checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" 1664 | dependencies = [ 1665 | "time-core", 1666 | ] 1667 | 1668 | [[package]] 1669 | name = "tinyvec" 1670 | version = "1.6.0" 1671 | source = "registry+https://github.com/rust-lang/crates.io-index" 1672 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1673 | dependencies = [ 1674 | "tinyvec_macros", 1675 | ] 1676 | 1677 | [[package]] 1678 | name = "tinyvec_macros" 1679 | version = "0.1.1" 1680 | source = "registry+https://github.com/rust-lang/crates.io-index" 1681 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1682 | 1683 | [[package]] 1684 | name = "tokio" 1685 | version = "1.27.0" 1686 | source = "registry+https://github.com/rust-lang/crates.io-index" 1687 | checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" 1688 | dependencies = [ 1689 | "autocfg", 1690 | "bytes", 1691 | "libc", 1692 | "mio", 1693 | "num_cpus", 1694 | "parking_lot", 1695 | "pin-project-lite", 1696 | "signal-hook-registry", 1697 | "socket2", 1698 | "tokio-macros", 1699 | "windows-sys 0.45.0", 1700 | ] 1701 | 1702 | [[package]] 1703 | name = "tokio-macros" 1704 | version = "2.0.0" 1705 | source = "registry+https://github.com/rust-lang/crates.io-index" 1706 | checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" 1707 | dependencies = [ 1708 | "proc-macro2", 1709 | "quote", 1710 | "syn 2.0.10", 1711 | ] 1712 | 1713 | [[package]] 1714 | name = "tokio-rustls" 1715 | version = "0.23.4" 1716 | source = "registry+https://github.com/rust-lang/crates.io-index" 1717 | checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" 1718 | dependencies = [ 1719 | "rustls", 1720 | "tokio", 1721 | "webpki", 1722 | ] 1723 | 1724 | [[package]] 1725 | name = "tokio-util" 1726 | version = "0.7.7" 1727 | source = "registry+https://github.com/rust-lang/crates.io-index" 1728 | checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" 1729 | dependencies = [ 1730 | "bytes", 1731 | "futures-core", 1732 | "futures-sink", 1733 | "pin-project-lite", 1734 | "tokio", 1735 | "tracing", 1736 | ] 1737 | 1738 | [[package]] 1739 | name = "tower-service" 1740 | version = "0.3.2" 1741 | source = "registry+https://github.com/rust-lang/crates.io-index" 1742 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1743 | 1744 | [[package]] 1745 | name = "tracing" 1746 | version = "0.1.37" 1747 | source = "registry+https://github.com/rust-lang/crates.io-index" 1748 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 1749 | dependencies = [ 1750 | "cfg-if", 1751 | "pin-project-lite", 1752 | "tracing-core", 1753 | ] 1754 | 1755 | [[package]] 1756 | name = "tracing-core" 1757 | version = "0.1.30" 1758 | source = "registry+https://github.com/rust-lang/crates.io-index" 1759 | checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" 1760 | dependencies = [ 1761 | "once_cell", 1762 | ] 1763 | 1764 | [[package]] 1765 | name = "try-lock" 1766 | version = "0.2.4" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" 1769 | 1770 | [[package]] 1771 | name = "typenum" 1772 | version = "1.16.0" 1773 | source = "registry+https://github.com/rust-lang/crates.io-index" 1774 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 1775 | 1776 | [[package]] 1777 | name = "unicase" 1778 | version = "2.6.0" 1779 | source = "registry+https://github.com/rust-lang/crates.io-index" 1780 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 1781 | dependencies = [ 1782 | "version_check", 1783 | ] 1784 | 1785 | [[package]] 1786 | name = "unicode-bidi" 1787 | version = "0.3.13" 1788 | source = "registry+https://github.com/rust-lang/crates.io-index" 1789 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 1790 | 1791 | [[package]] 1792 | name = "unicode-ident" 1793 | version = "1.0.8" 1794 | source = "registry+https://github.com/rust-lang/crates.io-index" 1795 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" 1796 | 1797 | [[package]] 1798 | name = "unicode-normalization" 1799 | version = "0.1.22" 1800 | source = "registry+https://github.com/rust-lang/crates.io-index" 1801 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1802 | dependencies = [ 1803 | "tinyvec", 1804 | ] 1805 | 1806 | [[package]] 1807 | name = "untrusted" 1808 | version = "0.7.1" 1809 | source = "registry+https://github.com/rust-lang/crates.io-index" 1810 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1811 | 1812 | [[package]] 1813 | name = "ureq" 1814 | version = "2.6.2" 1815 | source = "registry+https://github.com/rust-lang/crates.io-index" 1816 | checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d" 1817 | dependencies = [ 1818 | "base64 0.13.1", 1819 | "log", 1820 | "once_cell", 1821 | "rustls", 1822 | "rustls-native-certs", 1823 | "url", 1824 | "webpki", 1825 | "webpki-roots", 1826 | ] 1827 | 1828 | [[package]] 1829 | name = "url" 1830 | version = "2.3.1" 1831 | source = "registry+https://github.com/rust-lang/crates.io-index" 1832 | checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" 1833 | dependencies = [ 1834 | "form_urlencoded", 1835 | "idna", 1836 | "percent-encoding", 1837 | ] 1838 | 1839 | [[package]] 1840 | name = "users" 1841 | version = "0.11.0" 1842 | source = "registry+https://github.com/rust-lang/crates.io-index" 1843 | checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" 1844 | dependencies = [ 1845 | "libc", 1846 | "log", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "uuid" 1851 | version = "1.3.0" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" 1854 | dependencies = [ 1855 | "getrandom", 1856 | "serde", 1857 | ] 1858 | 1859 | [[package]] 1860 | name = "version_check" 1861 | version = "0.9.4" 1862 | source = "registry+https://github.com/rust-lang/crates.io-index" 1863 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1864 | 1865 | [[package]] 1866 | name = "want" 1867 | version = "0.3.0" 1868 | source = "registry+https://github.com/rust-lang/crates.io-index" 1869 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1870 | dependencies = [ 1871 | "log", 1872 | "try-lock", 1873 | ] 1874 | 1875 | [[package]] 1876 | name = "wasi" 1877 | version = "0.11.0+wasi-snapshot-preview1" 1878 | source = "registry+https://github.com/rust-lang/crates.io-index" 1879 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1880 | 1881 | [[package]] 1882 | name = "wasm-bindgen" 1883 | version = "0.2.84" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" 1886 | dependencies = [ 1887 | "cfg-if", 1888 | "wasm-bindgen-macro", 1889 | ] 1890 | 1891 | [[package]] 1892 | name = "wasm-bindgen-backend" 1893 | version = "0.2.84" 1894 | source = "registry+https://github.com/rust-lang/crates.io-index" 1895 | checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" 1896 | dependencies = [ 1897 | "bumpalo", 1898 | "log", 1899 | "once_cell", 1900 | "proc-macro2", 1901 | "quote", 1902 | "syn 1.0.109", 1903 | "wasm-bindgen-shared", 1904 | ] 1905 | 1906 | [[package]] 1907 | name = "wasm-bindgen-futures" 1908 | version = "0.4.34" 1909 | source = "registry+https://github.com/rust-lang/crates.io-index" 1910 | checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" 1911 | dependencies = [ 1912 | "cfg-if", 1913 | "js-sys", 1914 | "wasm-bindgen", 1915 | "web-sys", 1916 | ] 1917 | 1918 | [[package]] 1919 | name = "wasm-bindgen-macro" 1920 | version = "0.2.84" 1921 | source = "registry+https://github.com/rust-lang/crates.io-index" 1922 | checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" 1923 | dependencies = [ 1924 | "quote", 1925 | "wasm-bindgen-macro-support", 1926 | ] 1927 | 1928 | [[package]] 1929 | name = "wasm-bindgen-macro-support" 1930 | version = "0.2.84" 1931 | source = "registry+https://github.com/rust-lang/crates.io-index" 1932 | checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" 1933 | dependencies = [ 1934 | "proc-macro2", 1935 | "quote", 1936 | "syn 1.0.109", 1937 | "wasm-bindgen-backend", 1938 | "wasm-bindgen-shared", 1939 | ] 1940 | 1941 | [[package]] 1942 | name = "wasm-bindgen-shared" 1943 | version = "0.2.84" 1944 | source = "registry+https://github.com/rust-lang/crates.io-index" 1945 | checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" 1946 | 1947 | [[package]] 1948 | name = "wasm-streams" 1949 | version = "0.2.3" 1950 | source = "registry+https://github.com/rust-lang/crates.io-index" 1951 | checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" 1952 | dependencies = [ 1953 | "futures-util", 1954 | "js-sys", 1955 | "wasm-bindgen", 1956 | "wasm-bindgen-futures", 1957 | "web-sys", 1958 | ] 1959 | 1960 | [[package]] 1961 | name = "web-sys" 1962 | version = "0.3.61" 1963 | source = "registry+https://github.com/rust-lang/crates.io-index" 1964 | checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" 1965 | dependencies = [ 1966 | "js-sys", 1967 | "wasm-bindgen", 1968 | ] 1969 | 1970 | [[package]] 1971 | name = "webpki" 1972 | version = "0.22.0" 1973 | source = "registry+https://github.com/rust-lang/crates.io-index" 1974 | checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" 1975 | dependencies = [ 1976 | "ring", 1977 | "untrusted", 1978 | ] 1979 | 1980 | [[package]] 1981 | name = "webpki-roots" 1982 | version = "0.22.6" 1983 | source = "registry+https://github.com/rust-lang/crates.io-index" 1984 | checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" 1985 | dependencies = [ 1986 | "webpki", 1987 | ] 1988 | 1989 | [[package]] 1990 | name = "winapi" 1991 | version = "0.3.9" 1992 | source = "registry+https://github.com/rust-lang/crates.io-index" 1993 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1994 | dependencies = [ 1995 | "winapi-i686-pc-windows-gnu", 1996 | "winapi-x86_64-pc-windows-gnu", 1997 | ] 1998 | 1999 | [[package]] 2000 | name = "winapi-i686-pc-windows-gnu" 2001 | version = "0.4.0" 2002 | source = "registry+https://github.com/rust-lang/crates.io-index" 2003 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2004 | 2005 | [[package]] 2006 | name = "winapi-util" 2007 | version = "0.1.5" 2008 | source = "registry+https://github.com/rust-lang/crates.io-index" 2009 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 2010 | dependencies = [ 2011 | "winapi", 2012 | ] 2013 | 2014 | [[package]] 2015 | name = "winapi-x86_64-pc-windows-gnu" 2016 | version = "0.4.0" 2017 | source = "registry+https://github.com/rust-lang/crates.io-index" 2018 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2019 | 2020 | [[package]] 2021 | name = "windows-sys" 2022 | version = "0.42.0" 2023 | source = "registry+https://github.com/rust-lang/crates.io-index" 2024 | checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 2025 | dependencies = [ 2026 | "windows_aarch64_gnullvm", 2027 | "windows_aarch64_msvc", 2028 | "windows_i686_gnu", 2029 | "windows_i686_msvc", 2030 | "windows_x86_64_gnu", 2031 | "windows_x86_64_gnullvm", 2032 | "windows_x86_64_msvc", 2033 | ] 2034 | 2035 | [[package]] 2036 | name = "windows-sys" 2037 | version = "0.45.0" 2038 | source = "registry+https://github.com/rust-lang/crates.io-index" 2039 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 2040 | dependencies = [ 2041 | "windows-targets", 2042 | ] 2043 | 2044 | [[package]] 2045 | name = "windows-targets" 2046 | version = "0.42.2" 2047 | source = "registry+https://github.com/rust-lang/crates.io-index" 2048 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" 2049 | dependencies = [ 2050 | "windows_aarch64_gnullvm", 2051 | "windows_aarch64_msvc", 2052 | "windows_i686_gnu", 2053 | "windows_i686_msvc", 2054 | "windows_x86_64_gnu", 2055 | "windows_x86_64_gnullvm", 2056 | "windows_x86_64_msvc", 2057 | ] 2058 | 2059 | [[package]] 2060 | name = "windows_aarch64_gnullvm" 2061 | version = "0.42.2" 2062 | source = "registry+https://github.com/rust-lang/crates.io-index" 2063 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" 2064 | 2065 | [[package]] 2066 | name = "windows_aarch64_msvc" 2067 | version = "0.42.2" 2068 | source = "registry+https://github.com/rust-lang/crates.io-index" 2069 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" 2070 | 2071 | [[package]] 2072 | name = "windows_i686_gnu" 2073 | version = "0.42.2" 2074 | source = "registry+https://github.com/rust-lang/crates.io-index" 2075 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" 2076 | 2077 | [[package]] 2078 | name = "windows_i686_msvc" 2079 | version = "0.42.2" 2080 | source = "registry+https://github.com/rust-lang/crates.io-index" 2081 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" 2082 | 2083 | [[package]] 2084 | name = "windows_x86_64_gnu" 2085 | version = "0.42.2" 2086 | source = "registry+https://github.com/rust-lang/crates.io-index" 2087 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" 2088 | 2089 | [[package]] 2090 | name = "windows_x86_64_gnullvm" 2091 | version = "0.42.2" 2092 | source = "registry+https://github.com/rust-lang/crates.io-index" 2093 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" 2094 | 2095 | [[package]] 2096 | name = "windows_x86_64_msvc" 2097 | version = "0.42.2" 2098 | source = "registry+https://github.com/rust-lang/crates.io-index" 2099 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" 2100 | 2101 | [[package]] 2102 | name = "winreg" 2103 | version = "0.10.1" 2104 | source = "registry+https://github.com/rust-lang/crates.io-index" 2105 | checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" 2106 | dependencies = [ 2107 | "winapi", 2108 | ] 2109 | 2110 | [[package]] 2111 | name = "zerocopy" 2112 | version = "0.6.1" 2113 | source = "registry+https://github.com/rust-lang/crates.io-index" 2114 | checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236" 2115 | dependencies = [ 2116 | "byteorder", 2117 | "zerocopy-derive", 2118 | ] 2119 | 2120 | [[package]] 2121 | name = "zerocopy-derive" 2122 | version = "0.3.2" 2123 | source = "registry+https://github.com/rust-lang/crates.io-index" 2124 | checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3" 2125 | dependencies = [ 2126 | "proc-macro2", 2127 | "quote", 2128 | "syn 1.0.109", 2129 | ] 2130 | 2131 | [[package]] 2132 | name = "zeroize" 2133 | version = "1.6.0" 2134 | source = "registry+https://github.com/rust-lang/crates.io-index" 2135 | checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" 2136 | --------------------------------------------------------------------------------