xref: /aosp_15_r20/external/crosvm/disk/src/sys/windows.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::fs::File;
6 use std::io::Read;
7 use std::io::Seek;
8 use std::io::SeekFrom;
9 use std::os::windows::fs::OpenOptionsExt;
10 
11 use base::info;
12 use base::read_overlapped_blocking;
13 use cros_async::Executor;
14 use winapi::um::winbase::FILE_FLAG_NO_BUFFERING;
15 use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
16 use winapi::um::winnt::FILE_SHARE_READ;
17 
18 use crate::DiskFileParams;
19 use crate::Error;
20 use crate::Result;
21 use crate::SingleFileDisk;
22 
23 impl SingleFileDisk {
new(disk: File, ex: &Executor) -> Result<Self>24     pub fn new(disk: File, ex: &Executor) -> Result<Self> {
25         ex.async_overlapped_from(disk)
26             .map_err(Error::CreateSingleFileDisk)
27             .map(|inner| SingleFileDisk { inner })
28     }
29 }
30 
open_raw_disk_image(params: &DiskFileParams) -> Result<File>31 pub fn open_raw_disk_image(params: &DiskFileParams) -> Result<File> {
32     let mut options = File::options();
33     options.read(true).write(!params.is_read_only);
34     if params.lock {
35         if params.is_read_only {
36             // Shared read-only file access.
37             options.share_mode(FILE_SHARE_READ);
38         } else {
39             // Exclusive file access.
40             options.share_mode(0);
41         }
42     }
43 
44     let mut flags = 0;
45     if params.is_direct {
46         info!("Opening disk file with no buffering");
47         flags |= FILE_FLAG_NO_BUFFERING;
48     }
49     if params.is_overlapped {
50         info!("Opening disk file for overlapped IO");
51         flags |= FILE_FLAG_OVERLAPPED;
52     }
53     if flags != 0 {
54         options.custom_flags(flags);
55     }
56 
57     let raw_image = base::open_file_or_duplicate(&params.path, &options)
58         .map_err(|e| Error::OpenFile(params.path.display().to_string(), e))?;
59 
60     Ok(raw_image)
61 }
62 
63 /// On Windows, if the file is sparse, we set the option. On Linux this is not needed.
apply_raw_disk_file_options(raw_image: &File, is_sparse_file: bool) -> Result<()>64 pub fn apply_raw_disk_file_options(raw_image: &File, is_sparse_file: bool) -> Result<()> {
65     if is_sparse_file {
66         base::set_sparse_file(raw_image).map_err(Error::SetSparseFailure)?;
67     }
68     Ok(())
69 }
70 
read_from_disk( mut file: &File, offset: u64, buf: &mut [u8], overlapped_mode: bool, ) -> Result<()>71 pub fn read_from_disk(
72     mut file: &File,
73     offset: u64,
74     buf: &mut [u8],
75     overlapped_mode: bool,
76 ) -> Result<()> {
77     file.seek(SeekFrom::Start(offset))
78         .map_err(Error::SeekingFile)?;
79     if overlapped_mode {
80         read_overlapped_blocking(file, offset, buf)
81             .map(|_| ())
82             .map_err(Error::ReadingHeader)
83     } else {
84         file.read_exact(buf).map_err(Error::ReadingHeader)
85     }
86 }
87