diff --git a/uefi-test-runner/src/runtime/vars.rs b/uefi-test-runner/src/runtime/vars.rs index ebd57e08f..208a628fe 100644 --- a/uefi-test-runner/src/runtime/vars.rs +++ b/uefi-test-runner/src/runtime/vars.rs @@ -73,9 +73,13 @@ fn test_variables(rt: &RuntimeServices) { /// Test the variable functions in `uefi::runtime`. fn test_variables_freestanding() { + assert!(!runtime::variable_exists(NAME, VENDOR).unwrap()); + // Create the test variable. runtime::set_variable(NAME, VENDOR, ATTRS, VALUE).expect("failed to set variable"); + assert!(runtime::variable_exists(NAME, VENDOR).unwrap()); + // Test `get_variable` with too small of a buffer. let mut buf = [0u8; 0]; assert_eq!( @@ -106,6 +110,7 @@ fn test_variables_freestanding() { // Delete the variable and verify it can no longer be read. runtime::delete_variable(NAME, VENDOR).expect("failed to delete variable"); + assert!(!runtime::variable_exists(NAME, VENDOR).unwrap()); assert_eq!( runtime::get_variable(NAME, VENDOR, &mut buf) .unwrap_err() diff --git a/uefi/CHANGELOG.md b/uefi/CHANGELOG.md index c0faa59e5..e76dfd899 100644 --- a/uefi/CHANGELOG.md +++ b/uefi/CHANGELOG.md @@ -11,6 +11,7 @@ how to integrate the `uefi` crate into them. - Added `Handle::new`. - Added the `uefi::boot`, `uefi::runtime`, and `uefi::system` modules to the prelude. +- Added `runtime::variable_exists`. ## Changed - The `BootServices`, `RuntimeServices`, and `SystemTable` structs have been diff --git a/uefi/src/runtime.rs b/uefi/src/runtime.rs index 48c51380c..1d7d4545b 100644 --- a/uefi/src/runtime.rs +++ b/uefi/src/runtime.rs @@ -72,6 +72,47 @@ pub unsafe fn set_time(time: &Time) -> Result { (rt.set_time)(time.cast()).to_result() } +/// Checks if a variable exists. +/// +/// Returns `Ok(true)` if the variable exists, `Ok(false)` if the variable does +/// not exist, or `Err` if the existence of the variable could not be determined. +/// +/// # Errors +/// +/// * [`Status::DEVICE_ERROR`]: variable could not be read due to a hardware error. +/// * [`Status::SECURITY_VIOLATION`]: variable could not be read due to an +/// authentication error. +/// * [`Status::UNSUPPORTED`]: this platform does not support variable storage +/// after exiting boot services. +pub fn variable_exists(name: &CStr16, vendor: &VariableVendor) -> Result { + let rt = runtime_services_raw_panicking(); + let rt = unsafe { rt.as_ref() }; + + let attributes = ptr::null_mut(); + let data = ptr::null_mut(); + let mut data_size = 0; + + let status = unsafe { + (rt.get_variable)( + name.as_ptr().cast(), + &vendor.0, + attributes, + &mut data_size, + data, + ) + }; + + match status { + // If the variable exists, the status will be BUFFER_TOO_SMALL because + // data_size is 0. Empty variables do not exist, because setting a + // variable with empty data deletes the variable. In other words, the + // status will never be SUCCESS. + Status::BUFFER_TOO_SMALL => Ok(true), + Status::NOT_FOUND => Ok(false), + _ => Err(Error::from(status)), + } +} + /// Gets the contents and attributes of a variable. The size of `buf` must be at /// least as big as the variable's size, although it can be larger. ///