// Copyright 2019-2021 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT use serde::{ser::Serializer, Serialize}; use tauri::{ command, plugin::{Builder as PluginBuilder, TauriPlugin}, Runtime, }; use std::{ path::PathBuf, time::{SystemTime, UNIX_EPOCH}, }; #[cfg(unix)] use std::os::unix::fs::{MetadataExt, PermissionsExt}; #[cfg(windows)] use std::os::windows::fs::MetadataExt; type Result = std::result::Result; #[derive(Debug, thiserror::Error)] pub enum Error { #[error(transparent)] Io(#[from] std::io::Error), } impl Serialize for Error { fn serialize(&self, serializer: S) -> std::result::Result where S: Serializer, { serializer.serialize_str(self.to_string().as_ref()) } } #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct Permissions { readonly: bool, #[cfg(unix)] mode: u32, } #[cfg(unix)] #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct UnixMetadata { dev: u64, ino: u64, mode: u32, nlink: u64, uid: u32, gid: u32, rdev: u64, blksize: u64, blocks: u64, } #[derive(Serialize)] #[serde(rename_all = "camelCase")] struct Metadata { accessed_at_ms: u64, created_at_ms: u64, modified_at_ms: u64, is_dir: bool, is_file: bool, is_symlink: bool, size: u64, permissions: Permissions, #[cfg(unix)] #[serde(flatten)] unix: UnixMetadata, #[cfg(windows)] file_attributes: u32, } fn system_time_to_ms(time: std::io::Result) -> u64 { time.map(|t| { let duration_since_epoch = t.duration_since(UNIX_EPOCH).unwrap(); duration_since_epoch.as_millis() as u64 }) .unwrap_or_default() } #[command] async fn metadata(path: PathBuf) -> Result { let metadata = std::fs::metadata(path)?; let file_type = metadata.file_type(); let permissions = metadata.permissions(); Ok(Metadata { accessed_at_ms: system_time_to_ms(metadata.accessed()), created_at_ms: system_time_to_ms(metadata.created()), modified_at_ms: system_time_to_ms(metadata.modified()), is_dir: file_type.is_dir(), is_file: file_type.is_file(), is_symlink: file_type.is_symlink(), size: metadata.len(), permissions: Permissions { readonly: permissions.readonly(), #[cfg(unix)] mode: permissions.mode(), }, #[cfg(unix)] unix: UnixMetadata { dev: metadata.dev(), ino: metadata.ino(), mode: metadata.mode(), nlink: metadata.nlink(), uid: metadata.uid(), gid: metadata.gid(), rdev: metadata.rdev(), blksize: metadata.blksize(), blocks: metadata.blocks(), }, #[cfg(windows)] file_attributes: metadata.file_attributes(), }) } #[command] async fn exists(path: PathBuf) -> bool { path.exists() } pub fn init() -> TauriPlugin { PluginBuilder::new("fs-extra") .invoke_handler(tauri::generate_handler![exists, metadata]) .build() }