xref: /aosp_15_r20/external/crosvm/base/src/sys/windows/ioctl.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! Macros and wrapper functions for dealing with ioctls.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::size_of;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_int;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_ulong;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::*;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::ptr::null_mut;
12*bb4ee6a4SAndroid Build Coastguard Worker 
13*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::errhandlingapi::GetLastError;
14*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::ioapiset::DeviceIoControl;
15*bb4ee6a4SAndroid Build Coastguard Worker pub use winapi::um::winioctl::FILE_ANY_ACCESS;
16*bb4ee6a4SAndroid Build Coastguard Worker pub use winapi::um::winioctl::METHOD_BUFFERED;
17*bb4ee6a4SAndroid Build Coastguard Worker 
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor::AsRawDescriptor;
19*bb4ee6a4SAndroid Build Coastguard Worker use crate::errno_result;
20*bb4ee6a4SAndroid Build Coastguard Worker use crate::Result;
21*bb4ee6a4SAndroid Build Coastguard Worker 
22*bb4ee6a4SAndroid Build Coastguard Worker /// Raw macro to declare the expression that calculates an ioctl number
23*bb4ee6a4SAndroid Build Coastguard Worker #[macro_export]
24*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! device_io_control_expr {
25*bb4ee6a4SAndroid Build Coastguard Worker     // TODO (colindr) b/144440409: right now GVM is our only DeviceIOControl
26*bb4ee6a4SAndroid Build Coastguard Worker     //  target on windows, and it only uses METHOD_BUFFERED for the transfer
27*bb4ee6a4SAndroid Build Coastguard Worker     //  type and FILE_ANY_ACCESS for the required access, so we're going to
28*bb4ee6a4SAndroid Build Coastguard Worker     //  just use that for now. However, we may need to support more
29*bb4ee6a4SAndroid Build Coastguard Worker     //  options later.
30*bb4ee6a4SAndroid Build Coastguard Worker     ($dtype:expr, $code:expr) => {
31*bb4ee6a4SAndroid Build Coastguard Worker         $crate::windows::ctl_code(
32*bb4ee6a4SAndroid Build Coastguard Worker             $dtype,
33*bb4ee6a4SAndroid Build Coastguard Worker             $code,
34*bb4ee6a4SAndroid Build Coastguard Worker             $crate::windows::METHOD_BUFFERED,
35*bb4ee6a4SAndroid Build Coastguard Worker             $crate::windows::FILE_ANY_ACCESS,
36*bb4ee6a4SAndroid Build Coastguard Worker         ) as ::std::os::raw::c_ulong
37*bb4ee6a4SAndroid Build Coastguard Worker     };
38*bb4ee6a4SAndroid Build Coastguard Worker }
39*bb4ee6a4SAndroid Build Coastguard Worker 
40*bb4ee6a4SAndroid Build Coastguard Worker /// Raw macro to declare a function that returns an DeviceIOControl code.
41*bb4ee6a4SAndroid Build Coastguard Worker #[macro_export]
42*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! ioctl_ioc_nr {
43*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $dtype:expr, $code:expr) => {
44*bb4ee6a4SAndroid Build Coastguard Worker         #[allow(non_snake_case)]
45*bb4ee6a4SAndroid Build Coastguard Worker         pub const $name: ::std::os::raw::c_ulong = $crate::device_io_control_expr!($dtype, $code);
46*bb4ee6a4SAndroid Build Coastguard Worker     };
47*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $dtype:expr, $code:expr, $($v:ident),+) => {
48*bb4ee6a4SAndroid Build Coastguard Worker         #[allow(non_snake_case)]
49*bb4ee6a4SAndroid Build Coastguard Worker         pub fn $name($($v: ::std::os::raw::c_uint),+) -> ::std::os::raw::c_ulong {
50*bb4ee6a4SAndroid Build Coastguard Worker             $crate::device_io_control_expr!($dtype, $code)
51*bb4ee6a4SAndroid Build Coastguard Worker         }
52*bb4ee6a4SAndroid Build Coastguard Worker     };
53*bb4ee6a4SAndroid Build Coastguard Worker }
54*bb4ee6a4SAndroid Build Coastguard Worker 
55*bb4ee6a4SAndroid Build Coastguard Worker /// Declare an ioctl that transfers no data.
56*bb4ee6a4SAndroid Build Coastguard Worker #[macro_export]
57*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! ioctl_io_nr {
58*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $ty:expr, $nr:expr) => {
59*bb4ee6a4SAndroid Build Coastguard Worker         $crate::ioctl_ioc_nr!($name, $ty, $nr);
60*bb4ee6a4SAndroid Build Coastguard Worker     };
61*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $ty:expr, $nr:expr, $($v:ident),+) => {
62*bb4ee6a4SAndroid Build Coastguard Worker         $crate::ioctl_ioc_nr!($name, $ty, $nr, $($v),+);
63*bb4ee6a4SAndroid Build Coastguard Worker     };
64*bb4ee6a4SAndroid Build Coastguard Worker }
65*bb4ee6a4SAndroid Build Coastguard Worker 
66*bb4ee6a4SAndroid Build Coastguard Worker /// Declare an ioctl that reads data.
67*bb4ee6a4SAndroid Build Coastguard Worker #[macro_export]
68*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! ioctl_ior_nr {
69*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
70*bb4ee6a4SAndroid Build Coastguard Worker         $crate::ioctl_ioc_nr!(
71*bb4ee6a4SAndroid Build Coastguard Worker             $name,
72*bb4ee6a4SAndroid Build Coastguard Worker             $ty,
73*bb4ee6a4SAndroid Build Coastguard Worker             $nr
74*bb4ee6a4SAndroid Build Coastguard Worker         );
75*bb4ee6a4SAndroid Build Coastguard Worker     };
76*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
77*bb4ee6a4SAndroid Build Coastguard Worker         $crate::ioctl_ioc_nr!(
78*bb4ee6a4SAndroid Build Coastguard Worker             $name,
79*bb4ee6a4SAndroid Build Coastguard Worker             $ty,
80*bb4ee6a4SAndroid Build Coastguard Worker             $nr,
81*bb4ee6a4SAndroid Build Coastguard Worker             $($v),+
82*bb4ee6a4SAndroid Build Coastguard Worker         );
83*bb4ee6a4SAndroid Build Coastguard Worker     };
84*bb4ee6a4SAndroid Build Coastguard Worker }
85*bb4ee6a4SAndroid Build Coastguard Worker 
86*bb4ee6a4SAndroid Build Coastguard Worker /// Declare an ioctl that writes data.
87*bb4ee6a4SAndroid Build Coastguard Worker #[macro_export]
88*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! ioctl_iow_nr {
89*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
90*bb4ee6a4SAndroid Build Coastguard Worker         $crate::ioctl_ioc_nr!(
91*bb4ee6a4SAndroid Build Coastguard Worker             $name,
92*bb4ee6a4SAndroid Build Coastguard Worker             $ty,
93*bb4ee6a4SAndroid Build Coastguard Worker             $nr
94*bb4ee6a4SAndroid Build Coastguard Worker         );
95*bb4ee6a4SAndroid Build Coastguard Worker     };
96*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
97*bb4ee6a4SAndroid Build Coastguard Worker         $crate::ioctl_ioc_nr!(
98*bb4ee6a4SAndroid Build Coastguard Worker             $name,
99*bb4ee6a4SAndroid Build Coastguard Worker             $ty,
100*bb4ee6a4SAndroid Build Coastguard Worker             $nr,
101*bb4ee6a4SAndroid Build Coastguard Worker             $($v),+
102*bb4ee6a4SAndroid Build Coastguard Worker         );
103*bb4ee6a4SAndroid Build Coastguard Worker     };
104*bb4ee6a4SAndroid Build Coastguard Worker }
105*bb4ee6a4SAndroid Build Coastguard Worker 
106*bb4ee6a4SAndroid Build Coastguard Worker /// Declare an ioctl that reads and writes data.
107*bb4ee6a4SAndroid Build Coastguard Worker #[macro_export]
108*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! ioctl_iowr_nr {
109*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $ty:expr, $nr:expr, $size:ty) => {
110*bb4ee6a4SAndroid Build Coastguard Worker         $crate::ioctl_ioc_nr!(
111*bb4ee6a4SAndroid Build Coastguard Worker             $name,
112*bb4ee6a4SAndroid Build Coastguard Worker             $ty,
113*bb4ee6a4SAndroid Build Coastguard Worker             $nr
114*bb4ee6a4SAndroid Build Coastguard Worker         );
115*bb4ee6a4SAndroid Build Coastguard Worker     };
116*bb4ee6a4SAndroid Build Coastguard Worker     ($name:ident, $ty:expr, $nr:expr, $size:ty, $($v:ident),+) => {
117*bb4ee6a4SAndroid Build Coastguard Worker         $crate::ioctl_ioc_nr!(
118*bb4ee6a4SAndroid Build Coastguard Worker             $name,
119*bb4ee6a4SAndroid Build Coastguard Worker             $ty,
120*bb4ee6a4SAndroid Build Coastguard Worker             $nr,
121*bb4ee6a4SAndroid Build Coastguard Worker             $($v),+
122*bb4ee6a4SAndroid Build Coastguard Worker         );
123*bb4ee6a4SAndroid Build Coastguard Worker     };
124*bb4ee6a4SAndroid Build Coastguard Worker }
125*bb4ee6a4SAndroid Build Coastguard Worker 
126*bb4ee6a4SAndroid Build Coastguard Worker pub type IoctlNr = c_ulong;
127*bb4ee6a4SAndroid Build Coastguard Worker 
128*bb4ee6a4SAndroid Build Coastguard Worker /// Constructs an I/O control code.
129*bb4ee6a4SAndroid Build Coastguard Worker ///
130*bb4ee6a4SAndroid Build Coastguard Worker /// Shifts control code components into the appropriate bitfield locations:
131*bb4ee6a4SAndroid Build Coastguard Worker /// <https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/defining-i-o-control-codes>
ctl_code(device_type: u32, function: u32, method: u32, access: u32) -> IoctlNr132*bb4ee6a4SAndroid Build Coastguard Worker pub const fn ctl_code(device_type: u32, function: u32, method: u32, access: u32) -> IoctlNr {
133*bb4ee6a4SAndroid Build Coastguard Worker     (device_type << 16) | (access << 14) | (function << 2) | method
134*bb4ee6a4SAndroid Build Coastguard Worker }
135*bb4ee6a4SAndroid Build Coastguard Worker 
136*bb4ee6a4SAndroid Build Coastguard Worker /// Run an ioctl with no arguments.
137*bb4ee6a4SAndroid Build Coastguard Worker // (colindr) b/144457461 : This will probably not be used on windows.
138*bb4ee6a4SAndroid Build Coastguard Worker // It's only used on linux for the ioctls that override the exit code to
139*bb4ee6a4SAndroid Build Coastguard Worker // be the  return value of the ioctl. As far as I can tell, no DeviceIoControl
140*bb4ee6a4SAndroid Build Coastguard Worker // will do this, they will always instead return values in the output
141*bb4ee6a4SAndroid Build Coastguard Worker // buffer. So, as a result, we have no tests for this function, and
142*bb4ee6a4SAndroid Build Coastguard Worker // we may want to remove it if we never use it on windows, but we can't
143*bb4ee6a4SAndroid Build Coastguard Worker // remove it right now until we re-implement all the code that calls
144*bb4ee6a4SAndroid Build Coastguard Worker // this funciton for windows.
145*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
146*bb4ee6a4SAndroid Build Coastguard Worker /// The caller is responsible for determining the safety of the particular ioctl.
147*bb4ee6a4SAndroid Build Coastguard Worker /// This method should be safe as `DeviceIoControl` will handle error cases
148*bb4ee6a4SAndroid Build Coastguard Worker /// and it does size checking.
ioctl<F: AsRawDescriptor>(descriptor: &F, nr: IoctlNr) -> c_int149*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn ioctl<F: AsRawDescriptor>(descriptor: &F, nr: IoctlNr) -> c_int {
150*bb4ee6a4SAndroid Build Coastguard Worker     let mut byte_ret: c_ulong = 0;
151*bb4ee6a4SAndroid Build Coastguard Worker     let ret = DeviceIoControl(
152*bb4ee6a4SAndroid Build Coastguard Worker         descriptor.as_raw_descriptor(),
153*bb4ee6a4SAndroid Build Coastguard Worker         nr,
154*bb4ee6a4SAndroid Build Coastguard Worker         null_mut(),
155*bb4ee6a4SAndroid Build Coastguard Worker         0,
156*bb4ee6a4SAndroid Build Coastguard Worker         null_mut(),
157*bb4ee6a4SAndroid Build Coastguard Worker         0,
158*bb4ee6a4SAndroid Build Coastguard Worker         &mut byte_ret,
159*bb4ee6a4SAndroid Build Coastguard Worker         null_mut(),
160*bb4ee6a4SAndroid Build Coastguard Worker     );
161*bb4ee6a4SAndroid Build Coastguard Worker 
162*bb4ee6a4SAndroid Build Coastguard Worker     if ret == 1 {
163*bb4ee6a4SAndroid Build Coastguard Worker         return 0;
164*bb4ee6a4SAndroid Build Coastguard Worker     }
165*bb4ee6a4SAndroid Build Coastguard Worker 
166*bb4ee6a4SAndroid Build Coastguard Worker     GetLastError() as i32
167*bb4ee6a4SAndroid Build Coastguard Worker }
168*bb4ee6a4SAndroid Build Coastguard Worker 
169*bb4ee6a4SAndroid Build Coastguard Worker /// Run an ioctl with a single value argument.
170*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
171*bb4ee6a4SAndroid Build Coastguard Worker /// The caller is responsible for determining the safety of the particular ioctl.
172*bb4ee6a4SAndroid Build Coastguard Worker /// This method should be safe as `DeviceIoControl` will handle error cases
173*bb4ee6a4SAndroid Build Coastguard Worker /// and it does size checking.
ioctl_with_val( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, mut arg: c_ulong, ) -> c_int174*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn ioctl_with_val(
175*bb4ee6a4SAndroid Build Coastguard Worker     descriptor: &dyn AsRawDescriptor,
176*bb4ee6a4SAndroid Build Coastguard Worker     nr: IoctlNr,
177*bb4ee6a4SAndroid Build Coastguard Worker     mut arg: c_ulong,
178*bb4ee6a4SAndroid Build Coastguard Worker ) -> c_int {
179*bb4ee6a4SAndroid Build Coastguard Worker     let mut byte_ret: c_ulong = 0;
180*bb4ee6a4SAndroid Build Coastguard Worker 
181*bb4ee6a4SAndroid Build Coastguard Worker     let ret = DeviceIoControl(
182*bb4ee6a4SAndroid Build Coastguard Worker         descriptor.as_raw_descriptor(),
183*bb4ee6a4SAndroid Build Coastguard Worker         nr,
184*bb4ee6a4SAndroid Build Coastguard Worker         &mut arg as *mut c_ulong as *mut c_void,
185*bb4ee6a4SAndroid Build Coastguard Worker         size_of::<c_ulong>() as u32,
186*bb4ee6a4SAndroid Build Coastguard Worker         null_mut(),
187*bb4ee6a4SAndroid Build Coastguard Worker         0,
188*bb4ee6a4SAndroid Build Coastguard Worker         &mut byte_ret,
189*bb4ee6a4SAndroid Build Coastguard Worker         null_mut(),
190*bb4ee6a4SAndroid Build Coastguard Worker     );
191*bb4ee6a4SAndroid Build Coastguard Worker 
192*bb4ee6a4SAndroid Build Coastguard Worker     if ret == 1 {
193*bb4ee6a4SAndroid Build Coastguard Worker         return 0;
194*bb4ee6a4SAndroid Build Coastguard Worker     }
195*bb4ee6a4SAndroid Build Coastguard Worker 
196*bb4ee6a4SAndroid Build Coastguard Worker     GetLastError() as i32
197*bb4ee6a4SAndroid Build Coastguard Worker }
198*bb4ee6a4SAndroid Build Coastguard Worker 
199*bb4ee6a4SAndroid Build Coastguard Worker /// Run an ioctl with an immutable reference.
200*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
201*bb4ee6a4SAndroid Build Coastguard Worker /// The caller is responsible for determining the safety of the particular ioctl.
202*bb4ee6a4SAndroid Build Coastguard Worker /// Look at `ioctl_with_ptr` comments.
ioctl_with_ref<T>(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: &T) -> c_int203*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn ioctl_with_ref<T>(descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: &T) -> c_int {
204*bb4ee6a4SAndroid Build Coastguard Worker     ioctl_with_ptr(descriptor, nr, arg)
205*bb4ee6a4SAndroid Build Coastguard Worker }
206*bb4ee6a4SAndroid Build Coastguard Worker 
207*bb4ee6a4SAndroid Build Coastguard Worker /// Run an ioctl with a mutable reference.
208*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
209*bb4ee6a4SAndroid Build Coastguard Worker /// The caller is responsible for determining the safety of the particular ioctl.
210*bb4ee6a4SAndroid Build Coastguard Worker /// Look at `ioctl_with_ptr` comments.
ioctl_with_mut_ref<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: &mut T, ) -> c_int211*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn ioctl_with_mut_ref<T>(
212*bb4ee6a4SAndroid Build Coastguard Worker     descriptor: &dyn AsRawDescriptor,
213*bb4ee6a4SAndroid Build Coastguard Worker     nr: IoctlNr,
214*bb4ee6a4SAndroid Build Coastguard Worker     arg: &mut T,
215*bb4ee6a4SAndroid Build Coastguard Worker ) -> c_int {
216*bb4ee6a4SAndroid Build Coastguard Worker     ioctl_with_mut_ptr(descriptor, nr, arg)
217*bb4ee6a4SAndroid Build Coastguard Worker }
218*bb4ee6a4SAndroid Build Coastguard Worker 
219*bb4ee6a4SAndroid Build Coastguard Worker /// Run an ioctl with a raw pointer, specifying the size of the buffer.
220*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
221*bb4ee6a4SAndroid Build Coastguard Worker /// This method should be safe as `DeviceIoControl` will handle error cases
222*bb4ee6a4SAndroid Build Coastguard Worker /// and it does size checking. Also The caller should make sure `T` is valid.
ioctl_with_ptr_sized<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: *const T, size: usize, ) -> c_int223*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn ioctl_with_ptr_sized<T>(
224*bb4ee6a4SAndroid Build Coastguard Worker     descriptor: &dyn AsRawDescriptor,
225*bb4ee6a4SAndroid Build Coastguard Worker     nr: IoctlNr,
226*bb4ee6a4SAndroid Build Coastguard Worker     arg: *const T,
227*bb4ee6a4SAndroid Build Coastguard Worker     size: usize,
228*bb4ee6a4SAndroid Build Coastguard Worker ) -> c_int {
229*bb4ee6a4SAndroid Build Coastguard Worker     let mut byte_ret: c_ulong = 0;
230*bb4ee6a4SAndroid Build Coastguard Worker 
231*bb4ee6a4SAndroid Build Coastguard Worker     // We are trusting the DeviceIoControl function to not write anything
232*bb4ee6a4SAndroid Build Coastguard Worker     // to the input buffer. Just because it's a *const does not prevent
233*bb4ee6a4SAndroid Build Coastguard Worker     // the unsafe call from writing to it.
234*bb4ee6a4SAndroid Build Coastguard Worker     let ret = DeviceIoControl(
235*bb4ee6a4SAndroid Build Coastguard Worker         descriptor.as_raw_descriptor(),
236*bb4ee6a4SAndroid Build Coastguard Worker         nr,
237*bb4ee6a4SAndroid Build Coastguard Worker         arg as *mut c_void,
238*bb4ee6a4SAndroid Build Coastguard Worker         size as u32,
239*bb4ee6a4SAndroid Build Coastguard Worker         // We pass a null_mut as the output buffer.  If you expect
240*bb4ee6a4SAndroid Build Coastguard Worker         // an output, you should be calling the mut variant of this
241*bb4ee6a4SAndroid Build Coastguard Worker         // function.
242*bb4ee6a4SAndroid Build Coastguard Worker         null_mut(),
243*bb4ee6a4SAndroid Build Coastguard Worker         0,
244*bb4ee6a4SAndroid Build Coastguard Worker         &mut byte_ret,
245*bb4ee6a4SAndroid Build Coastguard Worker         null_mut(),
246*bb4ee6a4SAndroid Build Coastguard Worker     );
247*bb4ee6a4SAndroid Build Coastguard Worker 
248*bb4ee6a4SAndroid Build Coastguard Worker     if ret == 1 {
249*bb4ee6a4SAndroid Build Coastguard Worker         return 0;
250*bb4ee6a4SAndroid Build Coastguard Worker     }
251*bb4ee6a4SAndroid Build Coastguard Worker 
252*bb4ee6a4SAndroid Build Coastguard Worker     GetLastError() as i32
253*bb4ee6a4SAndroid Build Coastguard Worker }
254*bb4ee6a4SAndroid Build Coastguard Worker 
255*bb4ee6a4SAndroid Build Coastguard Worker /// Run an ioctl with a raw pointer.
256*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
257*bb4ee6a4SAndroid Build Coastguard Worker /// The caller is responsible for determining the safety of the particular ioctl.
258*bb4ee6a4SAndroid Build Coastguard Worker /// This method should be safe as `DeviceIoControl` will handle error cases
259*bb4ee6a4SAndroid Build Coastguard Worker /// and it does size checking. Also The caller should make sure `T` is valid.
ioctl_with_ptr<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: *const T, ) -> c_int260*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn ioctl_with_ptr<T>(
261*bb4ee6a4SAndroid Build Coastguard Worker     descriptor: &dyn AsRawDescriptor,
262*bb4ee6a4SAndroid Build Coastguard Worker     nr: IoctlNr,
263*bb4ee6a4SAndroid Build Coastguard Worker     arg: *const T,
264*bb4ee6a4SAndroid Build Coastguard Worker ) -> c_int {
265*bb4ee6a4SAndroid Build Coastguard Worker     ioctl_with_ptr_sized(descriptor, nr, arg, size_of::<T>())
266*bb4ee6a4SAndroid Build Coastguard Worker }
267*bb4ee6a4SAndroid Build Coastguard Worker 
268*bb4ee6a4SAndroid Build Coastguard Worker /// Run an ioctl with a mutable raw pointer.
269*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
270*bb4ee6a4SAndroid Build Coastguard Worker /// The caller is responsible for determining the safety of the particular ioctl.
271*bb4ee6a4SAndroid Build Coastguard Worker /// This method should be safe as `DeviceIoControl` will handle error cases
272*bb4ee6a4SAndroid Build Coastguard Worker /// and it does size checking. Also The caller should make sure `T` is valid.
ioctl_with_mut_ptr<T>( descriptor: &dyn AsRawDescriptor, nr: IoctlNr, arg: *mut T, ) -> c_int273*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn ioctl_with_mut_ptr<T>(
274*bb4ee6a4SAndroid Build Coastguard Worker     descriptor: &dyn AsRawDescriptor,
275*bb4ee6a4SAndroid Build Coastguard Worker     nr: IoctlNr,
276*bb4ee6a4SAndroid Build Coastguard Worker     arg: *mut T,
277*bb4ee6a4SAndroid Build Coastguard Worker ) -> c_int {
278*bb4ee6a4SAndroid Build Coastguard Worker     let mut byte_ret: c_ulong = 0;
279*bb4ee6a4SAndroid Build Coastguard Worker 
280*bb4ee6a4SAndroid Build Coastguard Worker     let ret = DeviceIoControl(
281*bb4ee6a4SAndroid Build Coastguard Worker         descriptor.as_raw_descriptor(),
282*bb4ee6a4SAndroid Build Coastguard Worker         nr,
283*bb4ee6a4SAndroid Build Coastguard Worker         arg as *mut c_void,
284*bb4ee6a4SAndroid Build Coastguard Worker         size_of::<T>() as u32,
285*bb4ee6a4SAndroid Build Coastguard Worker         arg as *mut c_void,
286*bb4ee6a4SAndroid Build Coastguard Worker         size_of::<T>() as u32,
287*bb4ee6a4SAndroid Build Coastguard Worker         &mut byte_ret,
288*bb4ee6a4SAndroid Build Coastguard Worker         null_mut(),
289*bb4ee6a4SAndroid Build Coastguard Worker     );
290*bb4ee6a4SAndroid Build Coastguard Worker 
291*bb4ee6a4SAndroid Build Coastguard Worker     if ret == 1 {
292*bb4ee6a4SAndroid Build Coastguard Worker         return 0;
293*bb4ee6a4SAndroid Build Coastguard Worker     }
294*bb4ee6a4SAndroid Build Coastguard Worker 
295*bb4ee6a4SAndroid Build Coastguard Worker     GetLastError() as i32
296*bb4ee6a4SAndroid Build Coastguard Worker }
297*bb4ee6a4SAndroid Build Coastguard Worker 
298*bb4ee6a4SAndroid Build Coastguard Worker /// Run a DeviceIoControl, specifying all options, only available on windows
299*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
300*bb4ee6a4SAndroid Build Coastguard Worker /// This method should be safe as `DeviceIoControl` will handle error cases
301*bb4ee6a4SAndroid Build Coastguard Worker /// for invalid paramters and takes input buffer and output buffer size
302*bb4ee6a4SAndroid Build Coastguard Worker /// arguments. Also The caller should make sure `T` is valid.
device_io_control<F: AsRawDescriptor, T, T2>( descriptor: &F, nr: IoctlNr, input: *const T, inputsize: u32, output: *mut T2, outputsize: u32, byte_ret: &mut c_ulong, ) -> Result<()>303*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn device_io_control<F: AsRawDescriptor, T, T2>(
304*bb4ee6a4SAndroid Build Coastguard Worker     descriptor: &F,
305*bb4ee6a4SAndroid Build Coastguard Worker     nr: IoctlNr,
306*bb4ee6a4SAndroid Build Coastguard Worker     input: *const T,
307*bb4ee6a4SAndroid Build Coastguard Worker     inputsize: u32,
308*bb4ee6a4SAndroid Build Coastguard Worker     output: *mut T2,
309*bb4ee6a4SAndroid Build Coastguard Worker     outputsize: u32,
310*bb4ee6a4SAndroid Build Coastguard Worker     byte_ret: &mut c_ulong,
311*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
312*bb4ee6a4SAndroid Build Coastguard Worker     let ret = DeviceIoControl(
313*bb4ee6a4SAndroid Build Coastguard Worker         descriptor.as_raw_descriptor(),
314*bb4ee6a4SAndroid Build Coastguard Worker         nr,
315*bb4ee6a4SAndroid Build Coastguard Worker         input as *mut c_void,
316*bb4ee6a4SAndroid Build Coastguard Worker         inputsize,
317*bb4ee6a4SAndroid Build Coastguard Worker         output as *mut c_void,
318*bb4ee6a4SAndroid Build Coastguard Worker         outputsize,
319*bb4ee6a4SAndroid Build Coastguard Worker         byte_ret,
320*bb4ee6a4SAndroid Build Coastguard Worker         null_mut(),
321*bb4ee6a4SAndroid Build Coastguard Worker     );
322*bb4ee6a4SAndroid Build Coastguard Worker 
323*bb4ee6a4SAndroid Build Coastguard Worker     if ret == 1 {
324*bb4ee6a4SAndroid Build Coastguard Worker         return Ok(());
325*bb4ee6a4SAndroid Build Coastguard Worker     }
326*bb4ee6a4SAndroid Build Coastguard Worker 
327*bb4ee6a4SAndroid Build Coastguard Worker     errno_result()
328*bb4ee6a4SAndroid Build Coastguard Worker }
329*bb4ee6a4SAndroid Build Coastguard Worker 
330*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
331*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
332*bb4ee6a4SAndroid Build Coastguard Worker 
333*bb4ee6a4SAndroid Build Coastguard Worker     use std::ffi::OsStr;
334*bb4ee6a4SAndroid Build Coastguard Worker     use std::fs::File;
335*bb4ee6a4SAndroid Build Coastguard Worker     use std::fs::OpenOptions;
336*bb4ee6a4SAndroid Build Coastguard Worker     use std::io::prelude::*;
337*bb4ee6a4SAndroid Build Coastguard Worker     use std::os::raw::*;
338*bb4ee6a4SAndroid Build Coastguard Worker     use std::os::windows::ffi::OsStrExt;
339*bb4ee6a4SAndroid Build Coastguard Worker     use std::os::windows::prelude::*;
340*bb4ee6a4SAndroid Build Coastguard Worker     use std::ptr::null_mut;
341*bb4ee6a4SAndroid Build Coastguard Worker 
342*bb4ee6a4SAndroid Build Coastguard Worker     use tempfile::tempdir;
343*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::fileapi::CreateFileW;
344*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::fileapi::OPEN_EXISTING;
345*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::winbase::SECURITY_SQOS_PRESENT;
346*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::winioctl::FSCTL_GET_COMPRESSION;
347*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::winioctl::FSCTL_SET_COMPRESSION;
348*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::winnt::COMPRESSION_FORMAT_LZNT1;
349*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::winnt::COMPRESSION_FORMAT_NONE;
350*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::winnt::FILE_SHARE_READ;
351*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::winnt::FILE_SHARE_WRITE;
352*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::winnt::GENERIC_READ;
353*bb4ee6a4SAndroid Build Coastguard Worker     use winapi::um::winnt::GENERIC_WRITE;
354*bb4ee6a4SAndroid Build Coastguard Worker 
355*bb4ee6a4SAndroid Build Coastguard Worker     // helper func, returns str as Vec<u16>
to_u16s<S: AsRef<OsStr>>(s: S) -> std::io::Result<Vec<u16>>356*bb4ee6a4SAndroid Build Coastguard Worker     fn to_u16s<S: AsRef<OsStr>>(s: S) -> std::io::Result<Vec<u16>> {
357*bb4ee6a4SAndroid Build Coastguard Worker         Ok(s.as_ref().encode_wide().chain(Some(0)).collect())
358*bb4ee6a4SAndroid Build Coastguard Worker     }
359*bb4ee6a4SAndroid Build Coastguard Worker 
360*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
361*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
ioct_get_and_set_compression()362*bb4ee6a4SAndroid Build Coastguard Worker     fn ioct_get_and_set_compression() {
363*bb4ee6a4SAndroid Build Coastguard Worker         let dir = tempdir().unwrap();
364*bb4ee6a4SAndroid Build Coastguard Worker         let file_path = dir.path().join("test.dat");
365*bb4ee6a4SAndroid Build Coastguard Worker         let file_path = file_path.as_path();
366*bb4ee6a4SAndroid Build Coastguard Worker 
367*bb4ee6a4SAndroid Build Coastguard Worker         // compressed = empty short for compressed status to be read into
368*bb4ee6a4SAndroid Build Coastguard Worker         let mut compressed: c_ushort = 0x0000;
369*bb4ee6a4SAndroid Build Coastguard Worker 
370*bb4ee6a4SAndroid Build Coastguard Worker         // open our random file and write "foo" in it
371*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = OpenOptions::new()
372*bb4ee6a4SAndroid Build Coastguard Worker             .write(true)
373*bb4ee6a4SAndroid Build Coastguard Worker             .create_new(true)
374*bb4ee6a4SAndroid Build Coastguard Worker             .open(file_path)
375*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
376*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(b"foo").expect("Failed to write bytes.");
377*bb4ee6a4SAndroid Build Coastguard Worker         f.sync_all().expect("Failed to sync all.");
378*bb4ee6a4SAndroid Build Coastguard Worker 
379*bb4ee6a4SAndroid Build Coastguard Worker         // read the compression status
380*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: safe because return value is checked.
381*bb4ee6a4SAndroid Build Coastguard Worker         let ecode = unsafe {
382*bb4ee6a4SAndroid Build Coastguard Worker             super::super::ioctl::ioctl_with_mut_ref(&f, FSCTL_GET_COMPRESSION, &mut compressed)
383*bb4ee6a4SAndroid Build Coastguard Worker         };
384*bb4ee6a4SAndroid Build Coastguard Worker 
385*bb4ee6a4SAndroid Build Coastguard Worker         // shouldn't error
386*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(ecode, 0);
387*bb4ee6a4SAndroid Build Coastguard Worker         // should not be compressed by default (not sure if this will be the case on
388*bb4ee6a4SAndroid Build Coastguard Worker         // all machines...)
389*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(compressed, COMPRESSION_FORMAT_NONE);
390*bb4ee6a4SAndroid Build Coastguard Worker 
391*bb4ee6a4SAndroid Build Coastguard Worker         // Now do a FSCTL_SET_COMPRESSED to set it to COMPRESSION_FORMAT_LZNT1.
392*bb4ee6a4SAndroid Build Coastguard Worker         compressed = COMPRESSION_FORMAT_LZNT1;
393*bb4ee6a4SAndroid Build Coastguard Worker 
394*bb4ee6a4SAndroid Build Coastguard Worker         // NOTE: Theoretically I should be able to open this file like so:
395*bb4ee6a4SAndroid Build Coastguard Worker         // let mut f = OpenOptions::new()
396*bb4ee6a4SAndroid Build Coastguard Worker         //     .access_mode(GENERIC_WRITE|GENERIC_WRITE)
397*bb4ee6a4SAndroid Build Coastguard Worker         //     .share_mode(FILE_SHARE_READ|FILE_SHARE_WRITE)
398*bb4ee6a4SAndroid Build Coastguard Worker         //     .open("test.dat").unwrap();
399*bb4ee6a4SAndroid Build Coastguard Worker         //
400*bb4ee6a4SAndroid Build Coastguard Worker         //   However, that does not work, and I'm not sure why.  Here's where
401*bb4ee6a4SAndroid Build Coastguard Worker         //   the underlying std code is doing a CreateFileW:
402*bb4ee6a4SAndroid Build Coastguard Worker         //   https://github.com/rust-lang/rust/blob/master/src/libstd/sys/windows/fs.rs#L260
403*bb4ee6a4SAndroid Build Coastguard Worker         //   For now I'm just going to leave this test as-is.
404*bb4ee6a4SAndroid Build Coastguard Worker         //
405*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: safe because return value is checked.
406*bb4ee6a4SAndroid Build Coastguard Worker         let f = unsafe {
407*bb4ee6a4SAndroid Build Coastguard Worker             File::from_raw_handle(CreateFileW(
408*bb4ee6a4SAndroid Build Coastguard Worker                 to_u16s(file_path).unwrap().as_ptr(),
409*bb4ee6a4SAndroid Build Coastguard Worker                 GENERIC_READ | GENERIC_WRITE,
410*bb4ee6a4SAndroid Build Coastguard Worker                 FILE_SHARE_READ | FILE_SHARE_WRITE,
411*bb4ee6a4SAndroid Build Coastguard Worker                 null_mut(),
412*bb4ee6a4SAndroid Build Coastguard Worker                 OPEN_EXISTING,
413*bb4ee6a4SAndroid Build Coastguard Worker                 // I read there's some security concerns if you don't use this
414*bb4ee6a4SAndroid Build Coastguard Worker                 SECURITY_SQOS_PRESENT,
415*bb4ee6a4SAndroid Build Coastguard Worker                 null_mut(),
416*bb4ee6a4SAndroid Build Coastguard Worker             ))
417*bb4ee6a4SAndroid Build Coastguard Worker         };
418*bb4ee6a4SAndroid Build Coastguard Worker 
419*bb4ee6a4SAndroid Build Coastguard Worker         let ecode =
420*bb4ee6a4SAndroid Build Coastguard Worker             // SAFETY: safe because return value is checked.
421*bb4ee6a4SAndroid Build Coastguard Worker             unsafe { super::super::ioctl::ioctl_with_ref(&f, FSCTL_SET_COMPRESSION, &compressed) };
422*bb4ee6a4SAndroid Build Coastguard Worker 
423*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(ecode, 0);
424*bb4ee6a4SAndroid Build Coastguard Worker         // set compressed short back to 0 for reading purposes,
425*bb4ee6a4SAndroid Build Coastguard Worker         // otherwise we can't be sure we're the FSCTL_GET_COMPRESSION
426*bb4ee6a4SAndroid Build Coastguard Worker         // is writing anything to the compressed pointer.
427*bb4ee6a4SAndroid Build Coastguard Worker         compressed = 0;
428*bb4ee6a4SAndroid Build Coastguard Worker 
429*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: safe because return value is checked.
430*bb4ee6a4SAndroid Build Coastguard Worker         let ecode = unsafe {
431*bb4ee6a4SAndroid Build Coastguard Worker             super::super::ioctl::ioctl_with_mut_ref(&f, FSCTL_GET_COMPRESSION, &mut compressed)
432*bb4ee6a4SAndroid Build Coastguard Worker         };
433*bb4ee6a4SAndroid Build Coastguard Worker 
434*bb4ee6a4SAndroid Build Coastguard Worker         // now should be compressed
435*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(ecode, 0);
436*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(compressed, COMPRESSION_FORMAT_LZNT1);
437*bb4ee6a4SAndroid Build Coastguard Worker 
438*bb4ee6a4SAndroid Build Coastguard Worker         drop(f);
439*bb4ee6a4SAndroid Build Coastguard Worker         // clean up
440*bb4ee6a4SAndroid Build Coastguard Worker         dir.close().expect("Failed to close the temp directory.");
441*bb4ee6a4SAndroid Build Coastguard Worker     }
442*bb4ee6a4SAndroid Build Coastguard Worker 
443*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg_attr(all(target_os = "windows", target_env = "gnu"), ignore)]
444*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
ioctl_with_val()445*bb4ee6a4SAndroid Build Coastguard Worker     fn ioctl_with_val() {
446*bb4ee6a4SAndroid Build Coastguard Worker         let dir = tempdir().unwrap();
447*bb4ee6a4SAndroid Build Coastguard Worker         let file_path = dir.path().join("test.dat");
448*bb4ee6a4SAndroid Build Coastguard Worker         let file_path = file_path.as_path();
449*bb4ee6a4SAndroid Build Coastguard Worker 
450*bb4ee6a4SAndroid Build Coastguard Worker         // compressed = empty short for compressed status to be read into
451*bb4ee6a4SAndroid Build Coastguard Worker         // Now do a FSCTL_SET_COMPRESSED to set it to COMPRESSION_FORMAT_LZNT1.
452*bb4ee6a4SAndroid Build Coastguard Worker         let mut compressed: c_ushort = COMPRESSION_FORMAT_LZNT1;
453*bb4ee6a4SAndroid Build Coastguard Worker 
454*bb4ee6a4SAndroid Build Coastguard Worker         // open our random file and write "foo" in it
455*bb4ee6a4SAndroid Build Coastguard Worker         let mut f = OpenOptions::new()
456*bb4ee6a4SAndroid Build Coastguard Worker             .write(true)
457*bb4ee6a4SAndroid Build Coastguard Worker             .create_new(true)
458*bb4ee6a4SAndroid Build Coastguard Worker             .open(file_path)
459*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
460*bb4ee6a4SAndroid Build Coastguard Worker         f.write_all(b"foo").expect("Failed to write bytes.");
461*bb4ee6a4SAndroid Build Coastguard Worker         f.sync_all().expect("Failed to sync all.");
462*bb4ee6a4SAndroid Build Coastguard Worker 
463*bb4ee6a4SAndroid Build Coastguard Worker         // NOTE: Theoretically I should be able to open this file like so:
464*bb4ee6a4SAndroid Build Coastguard Worker         // let mut f = OpenOptions::new()
465*bb4ee6a4SAndroid Build Coastguard Worker         //     .access_mode(GENERIC_WRITE|GENERIC_WRITE)
466*bb4ee6a4SAndroid Build Coastguard Worker         //     .share_mode(FILE_SHARE_READ|FILE_SHARE_WRITE)
467*bb4ee6a4SAndroid Build Coastguard Worker         //     .open("test.dat").unwrap();
468*bb4ee6a4SAndroid Build Coastguard Worker         //
469*bb4ee6a4SAndroid Build Coastguard Worker         //   However, that does not work, and I'm not sure why.  Here's where
470*bb4ee6a4SAndroid Build Coastguard Worker         //   the underlying std code is doing a CreateFileW:
471*bb4ee6a4SAndroid Build Coastguard Worker         //   https://github.com/rust-lang/rust/blob/master/src/libstd/sys/windows/fs.rs#L260
472*bb4ee6a4SAndroid Build Coastguard Worker         //   For now I'm just going to leave this test as-is.
473*bb4ee6a4SAndroid Build Coastguard Worker         //
474*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: safe because return value is checked.
475*bb4ee6a4SAndroid Build Coastguard Worker         let f = unsafe {
476*bb4ee6a4SAndroid Build Coastguard Worker             File::from_raw_handle(CreateFileW(
477*bb4ee6a4SAndroid Build Coastguard Worker                 to_u16s(file_path).unwrap().as_ptr(),
478*bb4ee6a4SAndroid Build Coastguard Worker                 GENERIC_READ | GENERIC_WRITE,
479*bb4ee6a4SAndroid Build Coastguard Worker                 FILE_SHARE_READ | FILE_SHARE_WRITE,
480*bb4ee6a4SAndroid Build Coastguard Worker                 null_mut(),
481*bb4ee6a4SAndroid Build Coastguard Worker                 OPEN_EXISTING,
482*bb4ee6a4SAndroid Build Coastguard Worker                 // I read there's some security concerns if you don't use this
483*bb4ee6a4SAndroid Build Coastguard Worker                 SECURITY_SQOS_PRESENT,
484*bb4ee6a4SAndroid Build Coastguard Worker                 null_mut(),
485*bb4ee6a4SAndroid Build Coastguard Worker             ))
486*bb4ee6a4SAndroid Build Coastguard Worker         };
487*bb4ee6a4SAndroid Build Coastguard Worker 
488*bb4ee6a4SAndroid Build Coastguard Worker         // now we call ioctl_with_val, which isn't particularly any more helpful than
489*bb4ee6a4SAndroid Build Coastguard Worker         // ioctl_with_ref except for the cases where the input is only a word long
490*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: safe because return value is checked.
491*bb4ee6a4SAndroid Build Coastguard Worker         let ecode = unsafe {
492*bb4ee6a4SAndroid Build Coastguard Worker             super::super::ioctl::ioctl_with_val(&f, FSCTL_SET_COMPRESSION, compressed.into())
493*bb4ee6a4SAndroid Build Coastguard Worker         };
494*bb4ee6a4SAndroid Build Coastguard Worker 
495*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(ecode, 0);
496*bb4ee6a4SAndroid Build Coastguard Worker         // set compressed short back to 0 for reading purposes,
497*bb4ee6a4SAndroid Build Coastguard Worker         // otherwise we can't be sure we're the FSCTL_GET_COMPRESSION
498*bb4ee6a4SAndroid Build Coastguard Worker         // is writing anything to the compressed pointer.
499*bb4ee6a4SAndroid Build Coastguard Worker         compressed = 0;
500*bb4ee6a4SAndroid Build Coastguard Worker 
501*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY: safe because return value is checked.
502*bb4ee6a4SAndroid Build Coastguard Worker         let ecode = unsafe {
503*bb4ee6a4SAndroid Build Coastguard Worker             super::super::ioctl::ioctl_with_mut_ref(&f, FSCTL_GET_COMPRESSION, &mut compressed)
504*bb4ee6a4SAndroid Build Coastguard Worker         };
505*bb4ee6a4SAndroid Build Coastguard Worker 
506*bb4ee6a4SAndroid Build Coastguard Worker         // now should be compressed
507*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(ecode, 0);
508*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(compressed, COMPRESSION_FORMAT_LZNT1);
509*bb4ee6a4SAndroid Build Coastguard Worker 
510*bb4ee6a4SAndroid Build Coastguard Worker         drop(f);
511*bb4ee6a4SAndroid Build Coastguard Worker         // clean up
512*bb4ee6a4SAndroid Build Coastguard Worker         dir.close().expect("Failed to close the temp directory.");
513*bb4ee6a4SAndroid Build Coastguard Worker     }
514*bb4ee6a4SAndroid Build Coastguard Worker }
515