| // Copyright 2023 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| //! Utilities for interacting with the disk. | |
| use std::{ | |
| os::unix::prelude::OsStrExt, | |
| path::{Path, PathBuf}, | |
| }; | |
| /// Get a disk partition device path. | |
| /// | |
| /// This handles inserting a 'p' before the number if needed and special cases | |
| /// for /dev/disk/by-id or /dev/disk/by-id. | |
| /// Please note: The path needs to be a child of either: | |
| /// - /dev | |
| /// - /dev/disk/by-path | |
| /// - /dev/disk/by-id | |
| pub fn get_partition_device<P: AsRef<Path>>(disk_device: P, num: u32) -> Option<PathBuf> { | |
| return match disk_device.as_ref().parent() { | |
| Some(path) => { | |
| if path.as_os_str() == "/dev" { | |
| return Some(get_partition_device_dev(disk_device, num)); | |
| } else if path.as_os_str() == "/dev/disk/by-id" | |
| || path.as_os_str() == "/dev/disk/by-path" | |
| { | |
| return Some(get_partition_device_by_path_or_id(disk_device, num)); | |
| } | |
| None | |
| } | |
| None => None, | |
| }; | |
| } | |
| fn get_partition_device_dev<P: AsRef<Path>>(disk_device: P, num: u32) -> PathBuf { | |
| let mut buf = disk_device.as_ref().as_os_str().to_os_string(); | |
| // If the disk path ends in a number, e.g. "/dev/nvme0n1", append | |
| // a "p" before the partition number. | |
| if let Some(byte) = buf.as_bytes().last() { | |
| if byte.is_ascii_digit() { | |
| buf.push("p"); | |
| } | |
| } | |
| buf.push(num.to_string()); | |
| PathBuf::from(buf) | |
| } | |
| fn get_partition_device_by_path_or_id<P: AsRef<Path>>(disk_device: P, num: u32) -> PathBuf { | |
| let mut buf = disk_device.as_ref().as_os_str().to_os_string(); | |
| // Both by-path and by-id have a -partX postfix. | |
| // E.g. partition 4 of `/dev/disk/by-id/nvme-eui.e8238fa6bf530001001b448b4566aa1a` is: | |
| // `/dev/disk/by-id/nvme-eui.e8238fa6bf530001001b448b4566aa1a-part4` | |
| buf.push(format!("-part{}", num)); | |
| PathBuf::from(buf) | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| #[test] | |
| fn test_get_partition_device() { | |
| // Testing /dev variants. | |
| let result = get_partition_device(Path::new("/dev/nvme0n1"), 4); | |
| assert!(result.is_some()); | |
| assert_eq!(Path::new("/dev/nvme0n1p4").to_path_buf(), result.unwrap()); | |
| let result = get_partition_device(Path::new("/dev/loop0"), 1); | |
| assert!(result.is_some()); | |
| assert_eq!(Path::new("/dev/loop0p1").to_path_buf(), result.unwrap()); | |
| let result = get_partition_device(Path::new("/dev/mmcblk0"), 2); | |
| assert!(result.is_some()); | |
| assert_eq!(Path::new("/dev/mmcblk0p2").to_path_buf(), result.unwrap()); | |
| let result = get_partition_device(Path::new("/dev/sda"), 3); | |
| assert!(result.is_some()); | |
| assert_eq!(Path::new("/dev/sda3").to_path_buf(), result.unwrap()); | |
| // Testing /dev/disk/by-id variants. | |
| let result = get_partition_device( | |
| Path::new("/dev/disk/by-id/nvme-eui.e8238fa6bf530001001b448b4566aa1a"), | |
| 3, | |
| ); | |
| assert!(result.is_some()); | |
| assert_eq!( | |
| Path::new("/dev/disk/by-id/nvme-eui.e8238fa6bf530001001b448b4566aa1a-part3") | |
| .to_path_buf(), | |
| result.unwrap() | |
| ); | |
| let result = get_partition_device(Path::new("/dev/disk/by-id/scsi-0PersistentDisk"), 2); | |
| assert!(result.is_some()); | |
| assert_eq!( | |
| Path::new("/dev/disk/by-id/scsi-0PersistentDisk-part2").to_path_buf(), | |
| result.unwrap() | |
| ); | |
| // Testing /dev/disk/by-path variants. | |
| let result = get_partition_device(Path::new("/dev/disk/by-path/pci-0000:00:1f.2-ata-1"), 1); | |
| assert!(result.is_some()); | |
| assert_eq!( | |
| Path::new("/dev/disk/by-path/pci-0000:00:1f.2-ata-1-part1").to_path_buf(), | |
| result.unwrap() | |
| ); | |
| let result = | |
| get_partition_device(Path::new("/dev/disk/by-path/pci-0000:04:00.0-nvme-1"), 4); | |
| assert!(result.is_some()); | |
| assert_eq!( | |
| Path::new("/dev/disk/by-path/pci-0000:04:00.0-nvme-1-part4").to_path_buf(), | |
| result.unwrap() | |
| ); | |
| } | |
| } |