pub const RENAME_INFORMATION = extern struct {
Flags: FLAGS,
RootDirectory: ?HANDLE,
FileNameLength: ULONG,
FileName: [PATH_MAX_WIDE]WCHAR,
pub fn init(opts: struct {
Flags: FLAGS = .{},
RootDirectory: ?HANDLE = null,
FileName: []const WCHAR,
}) RENAME_INFORMATION {
var fri: RENAME_INFORMATION = .{
.Flags = opts.Flags,
.RootDirectory = opts.RootDirectory,
.FileNameLength = @intCast(@sizeOf(WCHAR) * opts.FileName.len),
.FileName = undefined,
};
@memcpy(fri.FileName[0..opts.FileName.len], opts.FileName);
return fri;
}
pub const FLAGS = packed struct(ULONG) {
REPLACE_IF_EXISTS: bool = false,
POSIX_SEMANTICS: bool = false,
SUPPRESS_PIN_STATE_INHERITANCE: bool = false,
SUPPRESS_STORAGE_RESERVE_INHERITANCE: bool = false,
AVAILABLE_SPACE: enum(u2) {
NO_PRESERVE = 0b00,
NO_INCREASE = 0b01,
NO_DECREASE = 0b10,
PRESERVE = 0b11,
} = .NO_PRESERVE,
IGNORE_READONLY_ATTRIBUTE: bool = false,
RESIZE_SR: enum(u2) {
NO_FORCE = 0b00,
FORCE_TARGET = 0b01,
FORCE_SOURCE = 0b10,
FORCE = 0b11,
} = .NO_FORCE,
Reserved9: u23 = 0,
};
pub fn getFileName(ri: *const RENAME_INFORMATION) []const WCHAR {
return ri.FileName[0..@divExact(ri.FileNameLength, @sizeOf(WCHAR))];
}
pub fn toBuffer(fri: *RENAME_INFORMATION) []u8 {
const start: [*]u8 = @ptrCast(fri);
// The ABI size of the documented struct is 24 bytes, and attempting to use any size
// less than that will trigger INFO_LENGTH_MISMATCH, so enforce a minimum in cases where,
// for example, FileNameLength is 1 so only 22 bytes are technically needed.
const size = @max(24, @offsetOf(RENAME_INFORMATION, "FileName") + fri.FileNameLength);
return start[0..size];
}
}
This is not separated into RENAME_INFORMATION and RENAME_INFORMATION_EX because the only difference is the
Flagstype (BOOLEAN before _EX, ULONG in the _EX), which doesn't affect the struct layout--the offset of RootDirectory is the same regardless.