Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] #129504

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions src/bootstrap/src/chrisdenton.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#![allow(nonstandard_style)]
use std::ffi::c_void;
use std::os::windows::ffi::OsStrExt;
use std::os::windows::raw::HANDLE;
use std::path::Path;
use std::ptr::null_mut as null;
use std::{mem, ptr};

pub fn delete_with_info(path: &Path) -> Result<(), NTSTATUS> {
let orig_path = path;
unsafe {
let path = std::path::absolute(path).unwrap();
let path: Vec<u16> = r"\??\".encode_utf16().chain(path.as_os_str().encode_wide()).collect();
let s = UNICODE_STRING {
Length: (path.len() * 2) as _,
MaximumLength: (path.len() * 2) as _,
Buffer: path.as_ptr().cast_mut(),
};
let obj_attrs = OBJECT_ATTRIBUTES {
Length: mem::size_of::<OBJECT_ATTRIBUTES>() as _,
ObjectName: &s,
..mem::zeroed()
};
let mut io_status = mem::zeroed();
let mut handle = null();
let status = NtOpenFile(
&mut handle,
DELETE | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
&obj_attrs,
&mut io_status,
1 | 2 | 4,
FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT,
);
if status == STATUS_OBJECT_NAME_NOT_FOUND {
return Ok(());
} else if status < 0 {
panic!("status={:X} path={}", status, orig_path.display());
}
io_status = mem::zeroed();
let mut info: FILE_STAT_INFORMATION = mem::zeroed();
let status = NtQueryInformationFile(
handle,
&mut io_status,
ptr::from_mut(&mut info).cast(),
mem::size_of::<FILE_STAT_INFORMATION>() as _,
FileStatInformation,
);
if status < 0 {
CloseHandle(handle);
panic!("status={:X}", status);
}

let disposition = FILE_DISPOSITION_INFORMATION_EX {
Flags: FILE_DISPOSITION_DELETE
| FILE_DISPOSITION_POSIX_SEMANTICS
| FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE,
};
io_status = mem::zeroed();
let status = NtSetInformationFile(
handle,
&mut io_status,
ptr::from_ref(&disposition).cast(),
mem::size_of::<FILE_DISPOSITION_INFORMATION_EX>() as _,
FileDispositionInformationEx,
);
CloseHandle(handle);
println!("{info:#?}");
if status < 0 {
panic!("status={:X}", status);
}
}
Ok(())
}

pub fn last_nt_status() -> NTSTATUS {
unsafe { RtlGetLastNtStatus() }
}

#[repr(C)]
pub struct UNICODE_STRING {
pub Length: u16,
pub MaximumLength: u16,
pub Buffer: *mut u16,
}
#[repr(C)]
struct OBJECT_ATTRIBUTES {
Length: u32,
RootDirectory: HANDLE,
ObjectName: *const UNICODE_STRING,
Attributes: u32,
SecurityDescriptor: *const c_void,
SecurityQualityOfService: *const c_void,
}
#[repr(C)]
pub struct IO_STATUS_BLOCK {
Status: *mut (),
Information: usize,
}
#[derive(Debug)]
#[repr(C)]
pub struct FILE_STAT_INFORMATION {
FileId: i64,
CreationTime: i64,
LastAccessTime: i64,
LastWriteTime: i64,
ChangeTime: i64,
AllocationSize: i64,
EndOfFile: i64,
FileAttributes: u32,
ReparseTag: u32,
NumberOfLinks: u32,
EffectiveAccess: u32,
}
#[repr(C)]
struct FILE_DISPOSITION_INFORMATION_EX {
Flags: u32,
}
type NTSTATUS = i32;
const DELETE: u32 = 65536;
const SYNCHRONIZE: u32 = 1048576;
const FILE_READ_ATTRIBUTES: u32 = 128;
const FILE_SYNCHRONOUS_IO_NONALERT: u32 = 0x20;
const FILE_OPEN_REPARSE_POINT: u32 = 0x200000;
const FileStatInformation: i32 = 68;
const FileDispositionInformationEx: i32 = 64;
const FILE_DISPOSITION_DELETE: u32 = 1;
const FILE_DISPOSITION_POSIX_SEMANTICS: u32 = 2;
const FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE: u32 = 0x10;
pub const STATUS_OBJECT_NAME_NOT_FOUND: NTSTATUS = 0xC0000034_u32 as _;
//const STATUS_OBJECT_NAME_INVALID: NTSTATUS = 0xC0000033_u32 as _;

#[link(name = "ntdll", kind = "raw-dylib")]
extern "system" {
fn NtOpenFile(
FileHandle: *mut HANDLE,
DesiredAccess: u32,
ObjectAttributes: *const OBJECT_ATTRIBUTES,
IoStatusBlock: *mut IO_STATUS_BLOCK,
ShareAccess: u32,
OpenOptions: u32,
) -> NTSTATUS;
fn NtQueryInformationFile(
FileHandle: HANDLE,
IoStatusBlock: *mut IO_STATUS_BLOCK,
FileInformation: *mut (),
Length: u32,
FileInformationClass: i32,
) -> NTSTATUS;
fn NtSetInformationFile(
FileHandle: HANDLE,
IoStatusBlock: *mut IO_STATUS_BLOCK,
FileInformation: *const (),
Length: u32,
FileInformationClass: i32,
) -> NTSTATUS;
fn RtlGetLastNtStatus() -> NTSTATUS;
}
#[link(name = "kernel32", kind = "raw-dylib")]
extern "system" {
fn CloseHandle(hObject: HANDLE) -> i32;
}
19 changes: 12 additions & 7 deletions src/bootstrap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::OnceLock;
use std::time::SystemTime;
use std::{env, io, str};

use build_helper::ci::gha;
Expand All @@ -41,6 +40,8 @@ use crate::utils::helpers::{
self, dir_is_empty, exe, libdir, mtime, output, set_file_times, symlink_dir,
};

#[cfg(windows)]
mod chrisdenton;
mod core;
mod utils;

Expand Down Expand Up @@ -1663,14 +1664,17 @@ Executed at: {executed_at}"#,
if src == dst {
return;
}
if let Err(e) = fs::remove_file(dst) {
if cfg!(windows) && e.kind() != io::ErrorKind::NotFound {
// workaround for https://github.com/rust-lang/rust/issues/127126
// if removing the file fails, attempt to rename it instead.
let now = t!(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH));
let _ = fs::rename(dst, format!("{}-{}", dst.display(), now.as_nanos()));
#[cfg(not(windows))]
let _ = fs::remove_file(dst);
#[cfg(windows)]
if fs::remove_file(dst).is_err() {
let status = chrisdenton::last_nt_status();
if status != chrisdenton::STATUS_OBJECT_NAME_NOT_FOUND {
println!("remove_file failed: {status:#X}");
let _ = chrisdenton::delete_with_info(dst);
}
}

let metadata = t!(src.symlink_metadata(), format!("src = {}", src.display()));
let mut src = src.to_path_buf();
if metadata.file_type().is_symlink() {
Expand All @@ -1689,6 +1693,7 @@ Executed at: {executed_at}"#,
if let Err(e) = fs::copy(&src, dst) {
panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
}
println!("bootstrap: src metadata perms = {:#?}", metadata.permissions());
t!(fs::set_permissions(dst, metadata.permissions()));

// Restore file times because changing permissions on e.g. Linux using `chmod` can cause
Expand Down
Loading