fs4/windows/
async_impl.rs

1macro_rules! allocate_size {
2    ($file: ty) => {
3        pub async fn allocated_size(file: &$file) -> Result<u64> {
4            unsafe {
5                let mut info: FILE_STANDARD_INFO = mem::zeroed();
6
7                let ret = GetFileInformationByHandleEx(
8                    file.as_raw_handle() as HANDLE,
9                    FileStandardInfo,
10                    &mut info as *mut _ as *mut _,
11                    mem::size_of::<FILE_STANDARD_INFO>() as u32,
12                );
13
14                if ret == 0 {
15                    Err(Error::last_os_error())
16                } else {
17                    Ok(info.AllocationSize as u64)
18                }
19            }
20        }
21    };
22}
23
24macro_rules! allocate {
25    ($file: ty) => {
26        pub async fn allocate(file: &$file, len: u64) -> Result<()> {
27            if allocated_size(file).await? < len {
28                unsafe {
29                    let mut info: FILE_ALLOCATION_INFO = mem::zeroed();
30                    info.AllocationSize = len as i64;
31                    let ret = SetFileInformationByHandle(
32                        file.as_raw_handle() as HANDLE,
33                        FileAllocationInfo,
34                        &mut info as *mut _ as *mut _,
35                        mem::size_of::<FILE_ALLOCATION_INFO>() as u32,
36                    );
37                    if ret == 0 {
38                        return Err(Error::last_os_error());
39                    }
40                }
41            }
42            if file.metadata().await?.len() < len {
43                file.set_len(len).await
44            } else {
45                Ok(())
46            }
47        }
48    };
49}
50
51macro_rules! test_mod {
52    ($annotation:meta, $($use_stmt:item)*) => {
53        #[cfg(test)]
54        mod test {
55          extern crate tempfile;
56
57          $(
58              $use_stmt
59          )*
60
61          /// A file handle may not be exclusively locked multiple times, or exclusively locked and then
62          /// shared locked.
63          #[$annotation]
64          async fn lock_non_reentrant() {
65              let tempdir = tempfile::TempDir::with_prefix("fs4").unwrap();
66              let path = tempdir.path().join("fs4");
67              let file = fs::OpenOptions::new()
68                  .read(true)
69                  .write(true)
70                  .create(true)
71                  .open(&path)
72                  .await
73                  .unwrap();
74
75              // Multiple exclusive locks fails.
76              file.lock_exclusive().unwrap();
77              assert_eq!(
78                  file.try_lock_exclusive().unwrap(),
79                  false
80              );
81              file.unlock().unwrap();
82
83              // Shared then Exclusive locks fails.
84              file.lock_shared().unwrap();
85              assert_eq!(
86                  file.try_lock_exclusive().unwrap(),
87                  false
88              );
89          }
90
91          /// A file handle can hold an exclusive lock and any number of shared locks, all of which must
92          /// be unlocked independently.
93          #[$annotation]
94          async fn lock_layering() {
95              let tempdir = tempfile::TempDir::with_prefix("fs4").unwrap();
96              let path = tempdir.path().join("fs4");
97              let file = fs::OpenOptions::new()
98                  .read(true)
99                  .write(true)
100                  .create(true)
101                  .open(&path)
102                  .await
103                  .unwrap();
104
105              // Open two shared locks on the file, and then try and fail to open an exclusive lock.
106              file.lock_exclusive().unwrap();
107              file.lock_shared().unwrap();
108              file.lock_shared().unwrap();
109              assert_eq!(
110                  file.try_lock_exclusive().unwrap(),
111                  false,
112                  "the first try lock exclusive",
113              );
114
115              // Pop one of the shared locks and try again.
116              file.unlock().unwrap();
117              assert_eq!(
118                  file.try_lock_exclusive().unwrap(),
119                  false,
120                    "pop the first shared lock",
121              );
122
123              // Pop the second shared lock and try again.
124              file.unlock().unwrap();
125              assert_eq!(
126                  file.try_lock_exclusive().unwrap(),
127                  false,
128                    "pop the second shared lock",
129              );
130
131              // Pop the exclusive lock and finally succeed.
132              file.unlock().unwrap();
133              file.lock_exclusive().unwrap();
134          }
135
136          /// A file handle with multiple open locks will have all locks closed on drop.
137          #[$annotation]
138          async fn lock_layering_cleanup() {
139              let tempdir = tempfile::TempDir::with_prefix("fs4").unwrap();
140              let path = tempdir.path().join("fs4");
141              let file1 = fs::OpenOptions::new()
142                  .read(true)
143                  .write(true)
144                  .create(true)
145                  .open(&path)
146                  .await
147                  .unwrap();
148              let file2 = fs::OpenOptions::new()
149                  .read(true)
150                  .write(true)
151                  .create(true)
152                  .open(&path)
153                  .await
154                  .unwrap();
155
156              // Open two shared locks on the file, and then try and fail to open an exclusive lock.
157              file1.lock_shared().unwrap();
158              assert_eq!(
159                  file2.try_lock_exclusive().unwrap(),
160                  false
161              );
162
163              drop(file1);
164              file2.lock_exclusive().unwrap();
165          }
166        }
167    };
168}
169
170cfg_async_std! {
171    pub(crate) mod async_std_impl;
172}
173
174cfg_fs_err2_tokio! {
175    pub(crate) mod fs_err2_tokio_impl;
176}
177
178cfg_fs_err3_tokio! {
179    pub(crate) mod fs_err3_tokio_impl;
180}
181
182cfg_smol! {
183    pub(crate) mod smol_impl;
184}
185
186cfg_tokio! {
187    pub(crate) mod tokio_impl;
188}