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(¶ms.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