fn rename(&self, new: &Path, replace: bool) -> io::Result<()> {
// &self must be opened with DELETE permission
use std::iter;
#[cfg(target_arch = "x86")]
const STRUCT_SIZE: usize = 12;
#[cfg(target_arch = "x86_64")]
const STRUCT_SIZE: usize = 20;
// FIXME: check for internal NULs in 'new'
let mut data: Vec<u16> = iter::repeat(0u16)
.take(STRUCT_SIZE / 2)
.chain(new.as_os_str().encode_wide())
.collect();
data.push(0);
let size = data.len() * 2;
unsafe {
// Thanks to alignment guarantees on Windows this works
// (8 for 32-bit and 16 for 64-bit)
let info = data.as_mut_ptr() as *mut FILE_RENAME_INFO;
// The type of ReplaceIfExists is BOOL, but it actually expects a
// BOOLEAN. This means true is -1, not c::TRUE.
(*info).ReplaceIfExists = if replace { -1 } else { FALSE };
(*info).RootDirectory = ptr::null_mut();
(*info).FileNameLength = (size - STRUCT_SIZE) as DWORD;
cvt(SetFileInformationByHandle(
self.handle().raw(),
FileRenameInfo,
data.as_mut_ptr() as *mut _ as *mut _,
size as DWORD,
))?;
Ok(())
}
}
this code uses winapi which declare FILE_RENAME_INFO as
The way the windows-sys crate works (which the windows crate is built on top of) is that it's generated from a massive API database called win32metadata. This database, and its conversion, is not perfect. In particular, I think a lot of preprocessor stuff needs to be manually implememented into the win32metadata tools. I'm pretty sure that the online docs are generated from the database as well. There have been defects in the conversion previously, and it's definitely not unthinkable that this is another one.
Going by the theory that the safest assumption to make is that what's in the actual SDK is the Proper Thing™️: Writing FILE_RENAME_INFO in a source file and telling Visual Studio to show its definition reveals the following:
Mystery solved? It looks like the win32metadata database/tools are not equipped to handle these particular preprocessor conditionals. It's a little annoying that they don't at least make sure that their own online documentation is properly generated.
The reason the two structs are the same size is because of size and alignment. RootDirectory is a HANDLE which has an alignment of 8 on 64-bit applications and 4 on 32-bit applications. So it must be aligned to at least 4. A BOOLEAN is 1 byte so in the older version of the struct there's at least 3 bytes "wasted" in order to align RootDirectory. The newer struct makes use of thoes bytes.