Skip to content

Commit

Permalink
chore: PlaceholderFile
Browse files Browse the repository at this point in the history
  • Loading branch information
ho-229 committed Jun 23, 2024
1 parent 87e6b58 commit d9586e5
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 136 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
widestring = "1.0.2"
nt-time = "0.8.0"
memoffset = "0.6.4"
windows = { version = "0.33.0", features = [
"alloc",
Expand Down
30 changes: 16 additions & 14 deletions examples/sftp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ use thiserror::Error;
use widestring::{u16str, U16String};
use wincs::{
filter::{info, ticket, SyncFilter},
metadata::Metadata,
nt_time::FileTime,
placeholder::ConvertOptions,
placeholder_file::{Metadata, PlaceholderFile},
placeholder_file::PlaceholderFile,
request::Request,
CloudErrorKind, HydrationType, Placeholder, PopulationType, Registration, SecurityId,
SyncRootIdBuilder, WriteAt,
Expand Down Expand Up @@ -168,9 +170,9 @@ impl SyncFilter for Filter {
.read(&mut buffer)
.map_err(|_| CloudErrorKind::InvalidRequest)?;

if bytes_read % 4096 != 0 && position + (bytes_read as u64) < end {
let unaligned = bytes_read % 4096;
bytes_read = bytes_read - unaligned;
let unaligned = bytes_read % 4096;
if unaligned != 0 && position + (bytes_read as u64) < end {
bytes_read -= unaligned;
server_file
.seek(SeekFrom::Current(-(unaligned as i64)))
.unwrap();
Expand Down Expand Up @@ -239,8 +241,8 @@ impl SyncFilter for Filter {
(true, true) => {
self.sftp
.rename(
&src.strip_prefix(&base).unwrap(),
&dest.strip_prefix(&base).unwrap(),
src.strip_prefix(&base).unwrap(),
dest.strip_prefix(&base).unwrap(),
None,
)
.map_err(|_| CloudErrorKind::InvalidRequest)?;
Expand Down Expand Up @@ -285,16 +287,16 @@ impl SyncFilter for Filter {
let relative_path = path.strip_prefix(parent).unwrap();
PlaceholderFile::new(relative_path)
.metadata(
if stat.is_dir() {
Metadata::directory()
} else {
Metadata::file()
match stat.is_dir() {
true => Metadata::directory(),
false => Metadata::file(),
}
.size(stat.size.unwrap_or_default())
// .creation_time() // either the access time or write time, whichever is less
.last_access_time(stat.atime.unwrap_or_default())
.last_write_time(stat.mtime.unwrap_or_default())
.change_time(stat.mtime.unwrap_or_default()),
.accessed(
stat.atime
.and_then(|t| FileTime::from_unix_time(t as _).ok())
.unwrap_or_default(),
),
)
.mark_in_sync()
.overwrite()
Expand Down
7 changes: 4 additions & 3 deletions src/command/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use windows::{
use crate::{
command::executor::{execute, Command, Fallible},
error::CloudErrorKind,
placeholder_file::{Metadata, PlaceholderFile},
metadata::Metadata,
placeholder_file::PlaceholderFile,
request::{RawConnectionKey, RawTransferKey},
usn::Usn,
};
Expand Down Expand Up @@ -112,7 +113,7 @@ impl Fallible for Write<'_> {
#[derive(Debug)]
pub struct Update<'a> {
/// Whether or not to mark the placeholder as "synced."
pub mark_sync: bool,
pub mark_in_sync: bool,
/// Optional metadata to update.
pub metadata: Option<Metadata>,
/// Optional file blob to update.
Expand All @@ -130,7 +131,7 @@ impl Command for Update<'_> {
fn build(&self) -> CF_OPERATION_PARAMETERS_0 {
CF_OPERATION_PARAMETERS_0 {
RestartHydration: CF_OPERATION_PARAMETERS_0_4 {
Flags: if self.mark_sync {
Flags: if self.mark_in_sync {
CloudFilters::CF_OPERATION_RESTART_HYDRATION_FLAG_MARK_IN_SYNC
} else {
CloudFilters::CF_OPERATION_RESTART_HYDRATION_FLAG_NONE
Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod error;
/// Contains traits extending common structs from the [std][std].
pub mod ext;
pub mod filter;
pub mod metadata;
pub mod placeholder;
pub mod placeholder_file;
pub mod request;
Expand All @@ -18,7 +19,7 @@ pub mod utility;
pub use error::CloudErrorKind;
pub use filter::{info, ticket, SyncFilter};
pub use placeholder::Placeholder;
pub use placeholder_file::{BatchCreate, Metadata, PlaceholderFile};
pub use placeholder_file::{BatchCreate, PlaceholderFile};
pub use request::{Process, Request};
pub use root::{
active_roots, is_supported, Connection, HydrationPolicy, HydrationType, PopulationType,
Expand All @@ -28,6 +29,8 @@ pub use root::{
pub use usn::Usn;
pub use utility::{ReadAt, WriteAt};

pub use nt_time;

mod sealed {
pub trait Sealed {}
}
129 changes: 129 additions & 0 deletions src/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use std::fs;

use nt_time::FileTime;
use windows::Win32::Storage::{
CloudFilters::CF_FS_METADATA,
FileSystem::{FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_BASIC_INFO},
};

use crate::sealed;

/// The metadata for a [PlaceholderFile][crate::PlaceholderFile].
#[derive(Debug, Clone, Copy, Default)]
pub struct Metadata(pub(crate) CF_FS_METADATA);

impl Metadata {
pub fn file() -> Self {
Self(CF_FS_METADATA {
BasicInfo: FILE_BASIC_INFO {
FileAttributes: FILE_ATTRIBUTE_NORMAL.0,
..Default::default()
},
..Default::default()
})
}

pub fn directory() -> Self {
Self(CF_FS_METADATA {
BasicInfo: FILE_BASIC_INFO {
FileAttributes: FILE_ATTRIBUTE_DIRECTORY.0,
..Default::default()
},
..Default::default()
})
}

/// The time the file/directory was created.
pub fn created(mut self, time: FileTime) -> Self {
self.0.BasicInfo.CreationTime = time.try_into().unwrap();
self
}

/// The time the file/directory was last accessed.
pub fn accessed(mut self, time: FileTime) -> Self {
self.0.BasicInfo.LastAccessTime = time.try_into().unwrap();
self
}

/// The time the file/directory content was last written.
pub fn written(mut self, time: FileTime) -> Self {
self.0.BasicInfo.LastWriteTime = time.try_into().unwrap();
self
}

/// The time the file/directory content or metadata was changed.
pub fn changed(mut self, time: FileTime) -> Self {
self.0.BasicInfo.ChangeTime = time.try_into().unwrap();
self
}

/// The size of the file's content.
pub fn size(mut self, size: u64) -> Self {
self.0.FileSize = size as i64;
self
}

/// File attributes.
pub fn attributes(mut self, attributes: u32) -> Self {
self.0.BasicInfo.FileAttributes |= attributes;
self
}
}

pub trait MetadataExt: sealed::Sealed {
/// The time the file was changed in
/// [FILETIME](https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime) format.
fn change_time(self, time: i64) -> Self;

/// The time the file was last accessed in
/// [FILETIME](https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime) format.
fn last_access_time(self, time: i64) -> Self;

/// The time the file was last written to in
/// [FILETIME](https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime) format.
fn last_write_time(self, time: i64) -> Self;

/// The time the file was created in
/// [FILETIME](https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime) format.
fn creation_time(self, time: i64) -> Self;
}

impl MetadataExt for Metadata {
fn change_time(mut self, time: i64) -> Self {
self.0.BasicInfo.ChangeTime = time;
self
}

fn last_access_time(mut self, time: i64) -> Self {
self.0.BasicInfo.LastAccessTime = time;
self
}

fn last_write_time(mut self, time: i64) -> Self {
self.0.BasicInfo.LastWriteTime = time;
self
}

fn creation_time(mut self, time: i64) -> Self {
self.0.BasicInfo.CreationTime = time;
self
}
}

impl sealed::Sealed for Metadata {}

impl From<fs::Metadata> for Metadata {
fn from(metadata: fs::Metadata) -> Self {
use std::os::windows::fs::MetadataExt;
Self(CF_FS_METADATA {
BasicInfo: FILE_BASIC_INFO {
CreationTime: metadata.creation_time() as i64,
LastAccessTime: metadata.last_access_time() as i64,
LastWriteTime: metadata.last_write_time() as i64,
ChangeTime: metadata.last_write_time() as i64,
FileAttributes: metadata.file_attributes(),
},
FileSize: metadata.file_size() as i64,
})
}
}
7 changes: 4 additions & 3 deletions src/placeholder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use windows::{
},
};

use crate::{Metadata, Usn};
use crate::{metadata::Metadata, Usn};

/// The type of handle that the placeholder file/directory owns.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -422,13 +422,13 @@ impl<'a> UpdateOptions<'a> {
}

/// Disables on-demand population for directories.
pub fn no_more_children(mut self) -> Self {
pub fn has_no_children(mut self) -> Self {
self.flags |= CloudFilters::CF_UPDATE_FLAG_DISABLE_ON_DEMAND_POPULATION;
self
}

/// Enable on-demand population for directories.
pub fn has_more_children(mut self) -> Self {
pub fn has_children(mut self) -> Self {
self.flags |= CloudFilters::CF_UPDATE_FLAG_ENABLE_ON_DEMAND_POPULATION;
self
}
Expand Down Expand Up @@ -632,6 +632,7 @@ impl From<File> for Placeholder {
impl TryFrom<Placeholder> for File {
type Error = core::Error;

#[allow(clippy::missing_transmute_annotations)]
fn try_from(placeholder: Placeholder) -> core::Result<Self> {
match placeholder.handle.handle_type {
PlaceholderHandleType::Win32 => {
Expand Down
Loading

0 comments on commit d9586e5

Please sign in to comment.